向编程语言添加功能


55

您的任务是通过实现一个非常聪明的库,或者通过处理输入文本和/或调整编译过程,将特征附加到编程语言上。

想法:

  • 将PHP样式的演示文稿添加到C中(例如 <?c printf("Hello,"); ?> world!)。
  • 添加一个空合并运算符到非C#的一种语言中。
  • 将宏添加到PHP。
  • goto到JavaScript。
  • 将模式匹配添加到语言X。
  • 将名称空间支持添加到没有语言支持的语言中。
  • 使C看起来像PHP。
  • 使Haskell看起来像Pascal。
  • ...(可在评论部分中发表想法)

规则:

  • 把东西拿到桌上。不要只说“ Template Haskell”即可向Haskell添加元编程功能。这不是StackOverflow。
  • 整个实现应该适合一个屏幕(不包括示例)。
  • 不要将代码托管在专门用于此任务的外部站点上。
  • 最令人印象深刻或令人惊讶的功能获胜。

不必担心100%正确地实现该功能。离得很远!主要的挑战是弄清楚您想做什么,并恶毒地砍掉细节,直到计划好的工作变得可行。

例:

向C编程语言添加一个lambda运算符

初始方法:

好的,我知道我想使用libgc,以便我的lambda可以解决向上和向下的funarg问题。我想我需要做的第一件事是为C编程语言编写/查找一个解析器,然后我需要学习有关C的类型系统的所有知识。就类型而言,我必须弄清楚如何理解它。我需要实现类型推断,还是只需要按照给定的形式键入形式参数?CI中所有不知道的疯狂功能怎么办?

很明显,在C中正确实现lambda是一项艰巨的任务。忘记正确性!简化,简化。

更好:

向上拧螺丝,谁需要它们?使用GNU C的嵌套函数语句表达式,我也许可以做一些棘手的事情。我想用简洁的hacky代码展示C语言上惊人的语法转换,但是我什至不需要解析器。那可以等待另一天。

结果(需要GCC):

#include <stdio.h>
#include <stdlib.h>

#define lambda(d,e)({d;typeof(e)f(d){return(e);};f;})

#define map(F,A)({typeof(F)f=(F);typeof(*(A))*a=(A);({int i,l=((int*)(a))[-1]; \
typeof(f(*a))*r=(void*)((char*)malloc(sizeof(int)+l*sizeof(*r))+sizeof(int));  \
((int*)r)[-1]=l;for(i=0;i<l;i++)r[i]=f(a[i]);r;});})

#define convert_to(T) lambda(T x, x)
#define print(T, fmt) lambda(T x, printf(fmt "\n", x))

int main(void)
{
    int *array = 1 + (int[]){10, 1,2,3,4,5,6,7,8,9,10};
    map(print(int, "%d"), array);

    double *array2 = map(lambda(int x, (double)x * 0.5), array);
    map(print(double, "%.1f"), array2);

    long *array3 = map(convert_to(long), array2);
    map(print(long, "%ld"), array3);

    long product = 1;
    map(lambda(int x, product *= x), array);
    printf("product: %ld\n", product);

    return 0;
}

那很容易,不是吗?我什至扔了一个map宏使它变得有用和漂亮。


10
我认为Ken Thompson让我们全力以赴:0字节的代码。
dmckee 2011年

4
我不想创建一个完整的答案,但如果有人感兴趣,我已经向GNU C添加了类
理查德·罗斯三世

3
不知道这是否符合条件,但是我已经用C编写了一个延续示例。不过,只不过是全屏播放。
luser droog

1
我感谢谁复活了这个问题;对于提交,我有一个绝妙的主意。
乔纳森·范·马特雷

2
在C语言中添加一个lambda ...嘿,别那样看着我。
Leushenko

Answers:


27

Haskell中的OOP语法

import Prelude hiding ((.))
a . b = b a

对象可以具有以下属性:

[1,5,3,2].length -- 4
[1,5,3,2].maximum -- 5
'a'.succ -- 'b'

...和方法:

"Hello world!".take(5) -- "Hello"
"Hello world!".splitAt(2) -- ("He","llo world!")
"Hello world!".map(toUpper) -- "HELLO WORLD!"

2
我在某个地方看到这个运算符的写法&和定义如下(&) = flip ($)
swish 2014年

6
@swish我没有使用,&因为它是“地址”一元运算符(Haskell中指针的实现留给读者练习)。
lortabac 2014年

1
@swish您可以使用flip id
Sean D

24

goto 在JavaScript中?

我的第一个想法是功能方法 –向函数添加参数以指示应从何处开始执行,并结合使用switch语句和外循环以其自身的返回值重复调用该函数。不幸的是,这将阻止使用局部变量,因为它们会在每次goto时丢失其值。

我可以使用一条with语句并将所有变量声明移到函数的开头,但是必须有更好的方法。最终我想到了使用JavaScript的异常处理。实际上,乔尔·斯波尔斯基(Joel Spolsky)说:“我认为例外并不比“ goto的……”更好 –显然是完美的选择。

想法是将无限循环置于函数内部,仅由return语句或未捕获的异常终止。所有的goto,被视为异常,将被捕获在循环中以防止其终止。这是该方法的结果:

function rewriteGoTo(func) {
    var code = '(';
    code += func.toString()
        .replace(/^\s*(\w+)\s*:/gm, 'case "$1":')
        .replace('{', '{ var $_label = ""; function goTo(label) { $_label = label; throw goTo; } while(true) try { { switch($_label) { case "": ');
    code += '} return; } catch($_e) { if($_e !== goTo) throw $_e; } })';
    return code;
}

您可以这样使用它- 即使在ES5严格模式下 -在Internet Explorer(demo)中除外:

var test = eval(rewriteGoTo(function(before) {
    var i = 1;
    again: print(before + i);
    i = i + 1;
    if(i <= 10) goTo('again');
}));

[由于某种原因,Internet Explorer无法评估匿名函数的代码,因此必须为该函数命名(在重写之前),然后使用该名称进行调用。当然,这可能会违反严格模式的规则。]

这不允许跳转到位于块中的语句(直到Duff的设备这样的构造合法),但是我们可以处理(另一个自执行的重写函数),对吗?


1
甜!做得好,保持简单。有趣的琐事:如果goto是完全用JavaScript实现的(您可以使用goto它跳出任何范围,甚至是函数),则表示支持继续。
乔伊·亚当斯

22

#在Java中定义

我认为用Java实现宏会很有趣。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * defines the use of #define. Usage:
 *
 * #def toReplaceCanHaveNoSpaces replacement can have extra spaces
 *
 * must be at the beginning of the line (excluding starting spaces or tabs)
 * 
 * @author Quincunx
 */
public class Define {

    public static void main(String[] args) {
        if (args.length != 1) {
            err("Please provide exactly 1 argument");
        }
        File source = new File(args[0]);
        if (!source.exists()) {
            err("Supplied filepath does not point to an existing file");
        }
        if (!getExtension(args[0]).equalsIgnoreCase(".java")) {
            err("Supplied file is not of type .java");
        }
        ArrayList<String> sourceData = new ArrayList<>();
        ArrayList<String[]> replacements = new ArrayList<>();
        try {
            BufferedReader read = new BufferedReader(new FileReader(source));
            String data;
            while ((data = read.readLine()) != null) {
                sourceData.add(data);
            }
            read.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
        for (int index = 0; index < sourceData.size(); index++) {
            String line = sourceData.get(index);
            line = line.replaceAll("\t", "    ");
            for (String[] e : replacements) {
                line = line.replace(e[0], e[1]);
            }

            if (line.trim().charAt(0) != '#') {
                sourceData.set(index, line);
                continue;
            }
            while (line.charAt(0) != '#') {
                line = line.substring(1);
            }
            int indexOf = line.indexOf(" ");
            String type = line.substring(1, indexOf);

            switch (type) {
                case "def":
                case "define":
                    String toReplace = line.substring(indexOf + 1, line.indexOf(" ", indexOf + 1));
                    replacements.add(new String[]{toReplace, line.substring(line.indexOf(":") + 1)});
                    break;
                default:
                    err("The source code contains a # in which there is no correct type");
            }
        }

        try {
            BufferedWriter write = new BufferedWriter(new FileWriter(source));
            for (String s : sourceData) {
                write.write(s);
                write.newLine();
            }
            write.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void err(String message) {
        System.err.println(message);
        System.exit(1);
    }

    public static String getExtension(String filePath) {
        return filePath.substring(filePath.lastIndexOf("."));
    }

}

用法示例(转换为以前发布的代码;让我们感到奇怪):

#def @ o
#def ~ a
#def $ i
#def ` e
#d`f % m
#d`f ! {
#d`f & d
#&`f _ }
#&`f 2 (
#&`f 7 )
#&`f $%p@rt$@. $%p@rt j~v~.$@.
#&`f $%p@rtu. $%p@rt j~v~.ut$l.
#&`f ps publ$c st~t$c
#&`f Str Str$ng

$%p@rt$@.Buff`r`&R`~&`r;
$%p@rt$@.Buff`r`&Wr$t`r;
$%p@rt$@.F$l`;
$%p@rt$@.F$l`R`~&`r;
$%p@rt$@.F$l`Wr$t`r;
$%p@rt$@.IOExc`pt$@n;
$%p@rtu.Arr~yL$st;
$%p@rtu.l@gg$ng.L`v`l;
$%p@rtu.l@gg$ng.L@gg`r;

#d`f L$st Arr~yL$st
#d`f l@g; L@gg`r.g`tL@gg`r2D`f$n`.cl~ss.g`tN~m`277.l@g2L`v`l.SEVERE, null, `x7;    

publ$c cl~ss D`f$n` !

    ps v@$d %ain2Str[] ~rgs7!
        $f 2~rgs.l`ngth != 17 !
            `rr2"Pl`~s` pr@v$&` `x~ctly 1 ~rgu%`nt"7;
        _
        F$l` squrc` = n`w F$l`2~rgs[0]7;
        $f 2!sourc`.`x$sts277 !
            `rr2"Suppli`& f$l`p~th &@`s n@t p@int t@ ~n `x$st$ng f$l`"7;
        _
        $f 2!g`tExt`ns$@n2~rgs[0]7.`qu~lsIgn@r`C~s`2".j~v~"77 !
            `rr2"Suppl$`& f$l` $s n@t @f typ` .j~v~"7;
        _
        L$st<Str> s@urceDat~ = n`w List<>27;
        L$st<Str[]> repl~cem`nts = n`w L$st<>27;
        try !
            Buff`r`&R`a&`r r`a& = new Buff`redRe~&`r2n`w F$l`R`~&`r2s@urc`77;
            Str &~t~;
            wh$l` 22&~t~ = r`~&.r`~&L$n`277 != null7 !
                s@urc`D~t~.~&&2&ata7;
            _
            re~&.cl@se27;
        _ c~tch 2IOExc`ption ex7 !
            log;
        _
        f@r 2$nt $n&`x = 0; $ndex < s@urc`D~t~.s$z`27; $nd`x++7 !
            Str l$n` = s@urc`D~ta.get2index7;
            line = line.r`pl~c`All2"\t", "    "7;
            for 2Str[] ` : r`pl~c`%`nts7 {
                line = line.r`pl~c`2`[0], e[1]7;
            _

            if 2l$ne.tr$%27.ch~rAt207 != '#'7 !
                sourc`D~t~.s`t2$n&`x, l$n`7;
                c@nt$nu`;
            _
            wh$l` 2line.ch~rAt207 != '#'7 !
                l$ne = l$ne.substr$ng217;
            _
            $nt in&`xOf = line.$n&`xOf2" "7;
            Str typ` = line.substring21, indexOf7;

            sw$tch 2type7 !
                c~s` "&`f":
                c~s` "def$n`":
                    str t@R`pl~c` = line.substring2indexOf + 1, line.indexOf2" ", indexOf + 177;
                    r`pl~c`%`nts.~&&2n`w s\Str[]!t@R`place, line.substring2line.indexOf2":"7 + 17_7;
                    br`~k;
                def~ult:
                    err2"Th` s@urc` c@&` c@nt~$ns ~ # $n wh$ch th`r` i$s n@ c@rr`ct typ`"7;
            _
        _

        try !
            Buff`r`&Wr$ter wr$te = new BufferedWriter2new F$l1Wr$t1r2s@urc177;
            for 2Str s : s@urceData7 !
                wr$te.write2s7;
                wr$te.n`wLin`27;
            _
            wr$t`.cl@s`27;
        _ c~tch 2IOExc`pt$@n `x7 !
            l@g;
        _
    _

    ps v@$& `rr2Str m`ss~g`7 !
        Syst`%.`rr.pr$ntln2message7;
        Syst`%.`x$t217;
    _

    ps Str g`tExt`nsi@n2Str fileP~th7 !
        r`turn f$lePath.substr$ng2f$l`P~th.l~stInd`xOf2"."77;
    _

_

7
我在第二个区块中滚动,唯一的想法是“ ...沿着兔子洞向下”。
Soham Chowdhury 2014年

18

C语言中的Foreach

迭代数组(适用于静态数组,不适用于通过指针接收的数组)

//syntactic beauty
#define in ,    

//syntactic beauty's helper macro
#define foreach(a) _foreach(a)

//the real foreach macro
#define _foreach(e,arr)\
typeof (&arr[0]) e;\
for (e=&arr[0];e!=&arr[sizeof(arr)/sizeof(arr[0])];e++)

要测试它:

int int_arr[3]={10,20,30};    
char *strings[]={"Hello","World","Foreach","Test"};

foreach (num in int_arr) {
        printf ("num=%d\n",*num);
}

foreach (str in strings) {
        printf ("str=%s\n",*str);
}

结果:

num=10
num=20
num=30
str=Hello
str=World
str=Foreach
str=Test

17

C中的属性

Tomasz Wegrzanowski 通过故意进行段错误处理在纯C中实现属性在访问属性时对程序进行。

通过创建一个struct跨多个页面的对象来设置具有“属性”的对象,以确保该属性的内存地址与实际数据成员位于不同的页面中。该属性的页面被标记为“禁止访问”,以确保尝试访问该属性将导致段错误。然后,故障处理程序将找出导致该段错误的属性访问,并调用适当的函数来计算该属性的值,该值将存储在该属性的内存地址中。

故障处理程序还将数据页标记为只读,以确保计算值保持一致。下次尝试写入数据成员时,将触发segfault,该segfault的处理程序将数据页设置为可读写,将属性页设置为不可访问(指示需要重新计算)。


15

Common Lisp中的计算来源

我最初实现了来自。但这还不够。

受到计算型goto的启发,我决定实现计算型源。

(defmacro computed-come-from-tagbody (&rest statements)
  (let ((has-comp-come-from nil)
        (comp-come-from-var nil)
        (start-tag (gensym))
        (end-tag (gensym)))

    (let ((current-tag start-tag)
          (come-froms (make-hash-table :test #'eq)))

      (let ((clauses '()))
        (loop for statement in statements do
             (if (symbolp statement)
                 (setf current-tag statement))

             (cond
               ((and (consp statement)
                     (eql 'come-from (car statement)))

                (setf has-comp-come-from t)
                (setf (gethash (cadr statement) come-froms) current-tag))
               (t (push statement clauses))))


        (if (not has-comp-come-from)
            `(tagbody ,@(reverse clauses))
            (let ((res '())
                  (current-tag start-tag))
              (loop for clause in (reverse clauses) do
                   (cond
                     ((symbolp clause)
                      (push clause res)
                      (setf current-tag clause)
                      ;; check all vars for jumps
                      (push
                       `(progn ,@(loop for k being the hash-key of come-froms
                                    for v being the hash-value of come-froms collect
                                      `(when (eql ,k ,current-tag)
                                         (go ,v))))
                       res))
                     (t (push clause res))))
              `(macrolet ((come-from (idx)
                            (declare (ignore idx))
                            (error "Come-from cannot be used with another form.")))
                 (tagbody ,@(reverse res)))))))))

使用范例

(come-from x) ; whenever we're at the top of a labeled block and the value of x is equal to the label, jump back to this point.

对于标记体内的每个come-from声明,它将在每个标签处检查come-from变量是否等于当前标签,如果是,则跳转到相应的come-from声明。

招待员

(let ((x :repeat)
      (y :exit))
   (computed-come-from-tagbody
      :loop              ;; when x == :loop jump to :loop.  when y == :loop jump to :exit
      (come-from x)
      (format t "What is your name? ")
      (let ((name (read-line)))
         (terpri)
         (format t "Hello ~a~%" name)
         (print (string= name "exit"))
         (when (string= name "exit")
             (setf x nil
                   y :repeat)))
       :repeat           ;; when x = :repeat jump to loop, when y = :repeat jump to exit
       :exit             ;; when x = :exit jump to loop, when y = :exit jump to exit
       (come-from y)))

嘶嘶声

(let ((i 0)
      (x nil)
      (y nil))
   (computed-come-from-tagbody
       :loop
       (come-from x)
       (cond
         ((> i 100)  (setf x nil
                           y :end-iteration)) 
         (t (or (and (zerop (mod i 3)) (zerop (mod i 5)) (print "FizzBuzz"))
                (and (zerop (mod i 3)) (print "Fizz"))
                (and (zerop (mod i 5)) (print "Buzz"))
                (print i))  
            (incf i)
            (setf x :end-iteration)))
       :end-iteration
       :end
       (come-from y)
       (print "done")))

14

Ruby中的“自动字符串”

代码很简单:

def self.method_missing *a; a.join ' '; end

现在你可以做

print This is an automatic string #=> This is an automatic string
print hooray #=> hooray

x = code golf
print This is + ' ' + x + '!' #=> This is code golf!


13

将宏添加到PHP

我们可以仅使用C预处理器来完成此任务。

一个PHP脚本:

<?php

#define ERROR(str) trigger_error(#str, E_USER_ERROR)

function test() {
        ERROR(Oops);
}

通过cpp管道:

cpp < test.php

结果:

<?php

function test() {
 trigger_error("Oops", E_USER_ERROR);
}

使用C语言中不存在的PHP功能是否会打破?如heredocs。CPP的Afair与C的语法紧密相关。
乔伊,

1
我认为预处理器仅对输入进行分类,而不会试图使其有意义。An <<<HEREDOC不超过3左移或左移以及一个标识符:-)但是,这将在heredoc字符串中进行宏替换。
Arnaud Le Blanc

C预处理程序会在输出中添加额外的垃圾,因此您的示例将无法按预期
方式

1
一个grep -v ^#谁来解决这个问题。我想这足以解决这个问题:-)
Arnaud Le Blanc

10

Python中的模式匹配防护

def pattern_match(n, s="__fns"):
 s=n+s;g=globals()
 def m(f):
  def a(*r):
   for f in g[s]:
    if reduce(lambda c,t:c and eval(t[1:],{},dict(zip(f.func_code.co_varnames,r))),filter(lambda x:x and x[0]is"|",map(lambda x:x.strip(),f.func_doc.split("\n")))): return f(*r)
  g[n]=a;g[s]=(g.get(s)or[])+[f]
  return a
 return m

该函数的主体为288个字符。

模式匹配防护使您可以根据参数值使用完全不同的功能。尽管可以使用一系列if语句轻松地模拟它,但是模式匹配防护可以帮助分离代码段,这是进行疯狂的元编程的一个很好的借口。

pattern_match是一个装饰器,它创建一个新功能来实现模式匹配防护。以竖线(|)开头的各文档字符串中给出的每个“子功能”的条件。如果所有条件均真实评估,则运行该功能的版本。依次测试功能,直到找到匹配项。否则,None返回。

一个例子将有助于阐明:

@pattern_match("test1")
def test1_a(a, b, c):
    """
    This guard tests if a and c are positive

    | a > 0
    | c > 0
    """
    return a + b + c

@pattern_match("test1")
def test1_b(a, b, c):
    """
    This pattern only ensures b is positive

    | b > 0
    """
    return b + c

@pattern_match("test1")
def test1_c(a, b, c):
    """
    Final catchall

    | True
    """
    return 0


print test1(1,2,3) # (a) >>> 6
print test1(1,2,0) # (b) >>> 2
print test1(1,0,0) # (c) >>> 0
print test1(0,0,1) # (b) >>> 1

在Haskell中,这称为Guards,而不是模式匹配。在Haskell中,模式匹配可以说成f [a,b,c] = ...,它不仅针对谓词测试参数,而且在成功匹配后绑定各个变量。不过,这仍然很酷。
乔伊·亚当斯

'!感谢您纠正错误!我也在考虑Haskell,特别是专注于定义具有两个不同谓词(即f (x:xs) = ...f [] = ...)的函数。我不知何故地使警卫们陷入困境,但这就是我的|出发地。
zbanks 2011年

这不是打高尔夫球的挑战。如果需要,您可以更详细(更易读)!:)
ReyCharles


7

卢阿的海关运营商

Pogs 巧妙地滥用了Lua中的运算符重载,以允许定义自定义中缀运算符。我已经对此进行了扩展,以支持运算符分段(部分地将运算符与任一操作数一起应用)并像生成的函数一样调用结果对象。

---- implementation
function infix(f)
  local function g(self, x)
    return f(self[1] or x, self[2] or x)
  end

  local mt   = { __sub = g, __call = g }
  local self = {}
  return setmetatable(self,
           { __sub = function (lhs,rhs)
                       return rhs == self and setmetatable({ lhs, nil }, mt)
                                           or setmetatable({ nil, rhs }, mt)
                     end })
end

---- testing
local eq   = infix(function (a, b) return a == b end)
local ge   = infix(function (a, b) return a >= b end)

local comp = infix(function (a, b) return a < b and -1
                                       or a > b and  1
                                       or            0 end)

function filter(pred, xs)
  local res = {}
  for i=1,#xs do
    if pred(xs[i]) then table.insert(res, xs[i]) end
  end
  return res
end

print(1  -eq-  1)                                      --> true
print(1 -comp- 0)                                      --> 1
print((4 -ge)(1))                                      --> true
print(table.unpack(filter(ge- 0, {1,-4,3,2,-8,0})))    --> 1   3   2   0

7

JavaScript中的多行字符串

在这种针对多行字符串的精心设计的语法中,每个多行字符串都将以(function(){/*和换行符开头,再以换行符和开头*/}+'').split('\n').slice(1,-1).join('\n')

使用这种惊人的直观语法,我们最终可以使用多行字符串:

var string = (function(){/*
THIS IS A MULTILINE STRING
HOORAY!!!
*/}+'').split('\n').slice(1,-1).join('\n');

console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!

对于不喜欢我们简单语法的人,我们提供了我们神话般的新语言的编译器:

function compile(code)
{
    return code.replace("#{", "(function(){/*").replace("}#", "*/}+'').split('\n').slice(1,-1).join('\n')")
}

相同的示例,在编译语言版本中:

var string = #{
THIS IS A MULTILINE STRING
HOORAY!!!
}#;
console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!

1
由于某些原因,我无法放入*/多行字符串。在字符串中包含正则表达式时,这非常烦人!
FireFly 2014年

@FireFly实际上,我认为这仍然有效。突出的合成物变得很奇怪。
骄傲的haskeller 2014年

6

C#中的可切片列表(如Python)

我一直很喜欢python的slice表示法,并希望它在C#中可用

用法:

SliceList<int> list = new SliceList<int>() { 5, 6, 2, 3, 1, 6 };
var a = list["-1"];     // Grab the last element (6)
var b = list["-2:"];    // Grab the last two elements (1,6)
var c = list[":-2"];    // Grab all but the last two elements (5,6,2,3)
var d = list["::-1"];   // Reverse the list (6,1,3,2,6,5)
var e = list["::2"];    // Grab every second item (5,2,1)

代码,远不能证明错误:

public class SliceList<T> : List<T>
{
    public object this[string slice]
    {
        get
        {
            if (string.IsNullOrWhiteSpace(slice))
                return this.ToList();
            int[] values = { 0, Count, 1 };
            string[] data = slice.Split(':');
            for(int i = 0; i < data.Length; i++)
            {
                if (string.IsNullOrEmpty(data[i])) continue;
                int value;
                int.TryParse(data[i], out value);
                if(value < 0 && i < 2)
                    value += Count;
                values[i] = value;
            }
            if (data.Length == 1)
                return this[values[0]];
            int start = Math.Min(values[0], values[1]);
            int stop = Math.Max(values[0], values[1]);
            int step = values[2];
            int sign = Math.Sign(step);
            if (sign < 0)
            {
                var temp = start;
                start = stop-1;
                stop = temp-1;
            }

            SliceList<T> newList = new SliceList<T>();
            for (int i = start; i != stop; i += step)
                newList.Add(this[i]);

            return newList;
        }
    }
}

我很久以前就要求切片包含在.NET中,但仍然被忽略了:(
Ray

6

使C更简单

该代码使您可以编写类似于脚本语言的C程序。它具有诸如“ var”,“ is”,“ string”,“ plus”,“ equal”等关键字。它通过许多 define语句工作。

// pretty.c

#include<stdio.h>

#define function int
#define var int
#define is =
#define then {
#define do {
#define does {
#define end }
#define equal ==
#define notequal !=
#define greater >
#define less <
#define greaterequal >=
#define lessequal <=
#define display printf
#define otherwise }else{
#define increase ++
#define decrease --
#define plus +
#define minus -
#define times *
#define divide /
#define character char
#define string char*
#define integer int

这使您可以编写如下代码:

/*
Preprocessor abuse, Yay!
*/

#include "pretty.c"

function main() does
    var myVar is 1;
    if(myVar greater 2)then
        display("Yep\n");
    otherwise
        display("Nope\n");
    end

    for(var i is 0; i less 10; i increase)do
        display("Loop: %d\n", i);
    end

    string myString = "Hello";
    display(myString);
end

上面的内容扩展为:

int main() {
    int myVar = 1;
    if(myVar > 2){
        printf("Yep\n");
    }else{
        printf("Nope\n");
    }

    for(int i = 0; i < 10; i ++){
        printf("Loop: %d\n", i);
    }

    char* myString = "Hello";
    printf(myString);
}

可能并不太有用,但是我发现很有趣的是,您可以通过一堆#defines 来创建整个编程语言。


看起来像Javascript / Ruby混搭...
Beta Decay

几乎没有上限-使用足够复杂的#defines,您甚至可以给语言提供诸如异常处理和垃圾回收之类的东西同时仍将基本C层保留在下面。
Leushenko 2014年

5

Tcl

TCL没有do ... whiledo ... until左右...

proc do {body op expr} {
    uplevel 1 $body
    switch -exact -- $op {
        while {
            while {[uplevel 1 [list expr $expr]} {
                uplevel 1 $body
            }
        }
        until {
            while {![uplevel 1 [list expr $expr]} {
                 uplevel 1 $body
            }
        }
    }
}

例:

do {
    puts -nonewline "Are you sure? "
    flush stdout
    set result [gets stdin]
} while {[string is boolean -strict $result]}

uplevel 在调用者范围内执行脚本。


5

在PostScript中转到

我首先想到的是,我必须对exec堆栈进行修改,所以这个错误的开始会挖掘出继续操作符,以便从ghostscript(或xpost)中停止。

/_stopped_mark
{countexecstack array execstack dup length 2 sub get}
stopped pop def 

但是,这比这简单。因为文件句柄的所有重复文件的位置都是相同的(setfileposition消耗其参数,所以这是该函数唯一有用的语义)。

/LABELS 10 dict def 

/: { % n :  define label
    LABELS exch currentfile fileposition put 
} def 

/goto { % goto label
    currentfile exch LABELS exch get setfileposition
} def 

/x 0 def 

/here :
    /x x 1 add def 

    x 5 ne {
        /here goto
    } if

x =

它打印5

上面有一些限制。跳转不是立即发生的,而是在if-body返回顶层并且解释器再次从文件读取(而不是从包含if-body的数组读取)时发生的。此时,文件已重新定位,“ goto”生效。


而且这只是字典中的定义,因此您几乎可以使用任何类型的标签。
luser droog

您也可以使用进行绝对跳转currentfile <pos> setfileposition,从文件开始算起字节数。
luser droog

4

Symbol#to_proc 在Ruby中带有参数

Symbol#to_proc这可能是我编写真正简洁的Ruby代码最喜欢的技巧之一。假设你有

nums = [1, 2, 3, 4]
text = %w(this is a test)

你想的内容转换numstext浮子和大写单词分别。Symbol#to_proc使您可以缩短如下代码:

nums.map { |num| num.to_f }
text.map { |word| word.upcase }

对此:

nums.map(&:to_f)
text.map(&:upcase)

太棒了!但是,如果我们想将in nums中的每个元素提升为i幂,或者将in中的所有出现替换为in s*text怎么办?有什么办法可以缩短这样的代码?

nums.map { |num| num ** 1i }
nums.map { |word| word.gsub('s', '*') }

las,使用时没有简单的方法来传递参数Symbol#to_proc。我见过它做多种方式,但可能有两个最聪明的和可用的包括猴子修补Symbol类[ 12 ]。我将在下面说明第一种方法。

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

现在,您可以执行以下操作:

nums.map(&:**.with(1i))
text.map(&:gsub.with('s', '*'))
nums.take_while(&:<.with(3))
text.delete_if(&:[].with('is'))

3

JavaScript foreach

var arr = ["Seattle", "WA", "New York", "NY", "Chicago", "IL"];

function foreach(fn, arr) {
  var s = fn.toString();
  var args = s.substring(s.indexOf('(')+1,s.indexOf(')')).split(",");
  var argsLen = args.length;
  var len = arr.length;
  for (var i = 0; i < len; i+=argsLen) {
    var part = arr.slice(i, i+argsLen);
    fn.apply(undefined, part);
  }
}

foreach (function(city, state) {
  console.log(city + ', ' + state);
}, arr);

输出量

Seattle, WA
New York, NY
Chicago, IL

备用语法,更像Tcl。

// Tcl's foreach loop for javascript.
// Keys in loop are prefixed with "this".
function tclForeach(keys, values, fn) {
  var obj={}, klen=keys.length, vlen=values.length, j, i;
  for (i=0, klen=keys.length; i < klen; i++) obj[keys[i]]=null;
  for(i = 0; i < vlen; i+=klen) {
    for(j=klen; j--;) obj[keys[j]] = values[i+j];
    fn.apply(obj);
  }
}

tclForeach(["city","state"], arr, function() {
  console.log(this.city + ', ' + this.state);
});

这不是一个简单的方法,但是更有趣。它检查使用函数的参数列表。您可以使用此技巧更进一步,做一些非常酷的事情。
Joey Adams

1
我正准备使用Tcl风格的foreach。我添加了稍微不同的方法,更像Tcl。
wolfhammer 2014年

2

Haskell的Gotos

基本思想是可以使用do-notations中的最后一条语句来部分模拟gotos。例如:

main = do
  loop:
  print 3
  goto loop

相当于

main = do
  loop
loop = do
  print 3
  loop

因为执行将跳到最后一条语句,所以最好表达gotos。

因为这样做的方式,gotos仅在它们do直接位于顶级定义的块时才跳转。实际上,它是“调用x并忽略其余按词法查看的语句”,而不是“全部x并忽略其余的语句”,就像真正的goto。

最大的问题是,当无法从IO操作的中间离开执行时-甚至return没有;return如果不是最后一条语句,则不执行任何操作。

通过另do一块捕获其余的语句,可以克服这一点。

goto loop
print 3

变成

const loop $ do
print 3

print 3语句被do块捕获,因此loop成为最后一条语句。

此转换还支持在操作范围内存在的变量。这是通过记住范围内的变量并将其传递给操作来完成的。例如:

printer r = do
  loop:
  putStrLn r
  goto loop
  print "this isn't executed"

这简单地转换为:

printer r = do
  loop r
loop = do
  putStrLn r
  const (loop r) $ do
  print "this isn't executed"

一些注意事项:

另外,return undefined添加一条语句以确保捕获do块不为空。

因为有时捕获do块中会存在类型歧义,所以const我们不使用asTypeOf,这与相同,const但需要两个参数都具有相同的类型。

实际的实现(在javascript中):

function makeGoto(code)
{
    var vars = [] // the known variables

    // add the arguments to the functions to scope
    code.split('\n')[0].split('=')[0].split(' ').slice(1).forEach(function(varname){vars.push(varname)})
    return code.replace(/([ \t]*)([a-zA-Z]+):|([ \t]*)goto[ \t]+([a-zA-Z]+)|[ \t]+([a-zA-Z]+)[ \t]*<-/gm, function match(match, labelSpaces, label, gotoSpaces, goto, x)
        {
            if (label != undefined)
                return labelSpaces+label+" "+vars.join(' ')+"\n"+label+" "+vars.join(' ')+"=do ";
            else if(goto != undefined)
                return gotoSpaces+"asTypeOf("+goto+" "+vars.join(' ')+")$do\n"+gotoSpaces+"return undefined";
            else
            {
                vars.push(x);
                return match
            }
        })
}

举例:

main = do
    putSrtLn "a"
    goto label
    putStrLn "b"
    label:
    putStrLn "c"

变成:

main = do
    putStrLn "a"
    asTypeOf(label )$do
    return undefined
    putStrLn "b"
    label 
label =do 
    putStrLn "c"

输出:

a
c

值得说明return的是,在Haskell中,它是一个常规函数,与C / etc中的关键字无关。
FireFly 2014年

1

Python转到

goto.py

import sys, re
globals_ = globals()
def setglobals(g):
    global globals_
    globals_ = g
def goto(l):
    global globals_ 
    with open(sys.argv[0], "rb") as f:    
        data = f.read()
        data_ = data.split('\n')
    if isinstance(l, int):
        l-=1 if l > 0 else 0
    elif isinstance(l, str):
        r=re.search(r"^\s*(#{0}|(def|class)\s+{0})".format(l), data, re.MULTILINE)
        l=len(data_)-(data[r.start():].count("\n")) if r else len(data_)
    if 0 < l < len(data_) or 0 < (l*-1) <= len(data_):
        exec("".join(data_[l:]),globals_)
        sys.exit(1)

用法

setglobals(globals()) #Set the globals to be used in exec to this file's globals (if imports or other variables are needed)
goto(8) #Goto line 8
goto(-8)#Goto 8th last line
goto("label")#Goto first occurrence of #label
goto("funcName")#Goto definition of funcName
goto("className")#Goto definition of className

样本测试案例

import goto, sys
goto.goto(-1)
sys.exit(-1)

print "Asdf"

样本测试用例输出

Asdf

exec()有点有趣。如果使用不正确,可能会导致最大递归深度错误。


-2

//导入javascript,而无需在HTML页面中专门使用script标记

function i(u) {
  document.write("script src=\" + u + \"></script>");
}

i("http://www.mysite.com/myscript.js");

是的,我知道是me子。长度:99


@ user2509848:该线程未标记为代码高尔夫。
乔伊·亚当斯

您发布的内容script周围需要标签。那么新功能到底在哪里呢?
manatwork 2014年

@JoeyAdams糟糕,抱歉。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.