Добавить функцию в язык программирования [закрыто]


55

Ваша задача - привязать функцию к языку программирования, либо внедрив очень умную библиотеку, либо обработав вводимый текст и / или изменив процесс компиляции.

Идеи:

  • Добавьте чередование презентаций в стиле PHP в C (например <?c printf("Hello,"); ?> world!).
  • Добавьте оператор объединения нулей в один из тех языков, которые не являются C #.
  • Добавьте макросы в PHP.
  • Добавить gotoв JavaScript.
  • Добавить сопоставление с образцом для языка X.
  • Добавить поддержку пространства имен для языка, в котором его нет.
  • Сделать C похожим на PHP.
  • Сделай так, чтобы Хаскелл выглядел как Паскаль.
  • ... (не стесняйтесь публиковать идеи в разделе комментариев)

Правила:

  • Принеси что-нибудь на стол. Не просто говорите "Template Haskell", чтобы добавить средства метапрограммирования в Haskell. Это не StackOverflow.
  • Вся реализация должна умещаться в одном скрине (не считая примера).
  • Не размещайте код на внешнем сайте специально для этой задачи.
  • Наиболее впечатляющая или удивительная особенность побеждает.

Не беспокойтесь о правильной реализации этой функции. Отнюдь не! Основная задача - выяснить, что вы хотите сделать, и злобно вырезать детали, пока ваше запланированное начинание не станет возможным.

Пример:

Добавьте лямбда-оператор к языку программирования C.

Начальный подход:

Хорошо, я знаю, что хотел бы использовать libgc, чтобы мои лямбды решали проблемы funarg вверх и вниз. Я думаю, первое, что мне нужно сделать, это написать / найти синтаксический анализатор для языка программирования Си, а затем мне нужно узнать все о системе типов Си. Я должен был бы выяснить, как понять это, насколько типы идут. Должен ли я реализовать вывод типа или просто потребовать, чтобы формальный параметр был напечатан как заданный? Как насчет всех этих сумасшедших функций в CI, о которых я еще не знаю?

Совершенно очевидно, что правильная реализация лямбды в C была бы огромной задачей. Забудь о правильности! Упростите, упростите.

Лучше:

Вверните вверх funargs, кому они нужны? Я мог бы сделать что-то хитрое с вложенными функциями GNU C и выражениями операторов . Я хотел продемонстрировать удивительное синтаксическое преобразование на 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

4
Я не хочу создавать полный ответ, но я добавил классы в GNU C на случай, если кому-то будет интересно.
Ричард Дж. Росс III

3
Не уверен, что это правильно, но я написал пример продолжения в Си . Немного больше, чем скриншот.
luser droog

1
Спасибо всем, кто воскресил этот вопрос; У меня есть отличная идея для моего представления.
Джонатан Ван Матр

2
Добавьте лямбду в C ... эй, не смотри на меня так.
Леушенко,

Ответы:


27

Синтаксис ООП в Хаскеле

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

6
@swish Я не использовал, &потому что это унарный оператор 'address-of' (реализация указателей в Haskell оставлена ​​в качестве упражнения для читателя).
lortabac

1
@ SWISH вы можете сохранить персонажа (и цикл мозга) с помощьюflip id
Шон D

24

goto в JavaScript?

Моей первой мыслью был функциональный подход - добавить параметр в функцию, чтобы указать, где должно начинаться выполнение, используя его с switchоператором и внешним циклом, многократно вызывающим функцию для ее собственного возвращаемого значения . К сожалению, это исключает использование локальных переменных, поскольку они теряют свои значения при каждом переходе.

Я мог бы использовать withоператор и переместить все объявления переменных в начало функции, но должен был быть лучший путь. В конце концов мне пришло в голову использовать обработку исключений в JavaScript . На самом деле, Джоэл Спольски сказал: «Я считаю, что исключения не лучше, чем« goto's ... » - очевидно, идеально подходят.

Идея заключалась в том, чтобы поместить внутри функции бесконечный цикл, завершаемый только returnоператором или необработанным исключением. Все gotos, рассматриваемые как исключения, будут перехвачены в цикле, чтобы предотвратить его завершение. Вот результат этого подхода:

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 ( демо ):

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

[Internet Explorer по какой-то причине не может оценить код анонимной функции, поэтому нужно было бы присвоить этой функции имя (до перезаписи) и вызывать ее, используя это имя. Конечно, это, вероятно, нарушило бы строгие правила режима.]

Это не позволяет переходить к оператору, расположенному внутри блока (до тех пор, пока такие конструкции, как устройство Даффа, не станут легальными), но мы можем справиться с этим (другая, самопроизвольно переписанная функция), верно?


1
Сладкий! Хорошая работа, все просто. Интересная мелочь: если бы она gotoбыла полностью реализована в JavaScript (там, где вы могли бы использовать ее gotoдля выпрыгивания из любой области видимости, даже из функции ), это подразумевало бы поддержку продолжений.
Джои Адамс

22

#define в 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
Я просматривал второй блок, и моей единственной мыслью было «... вниз по кроличьей норе».
Сохам Чоудхури

18

Foreach в C

Итерация массивов (работает со статическими массивами, а не с массивами, полученными через указатель)

//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, преднамеренно сегментируя программу при обращении к свойству.

Объект со «свойством» настраивается путем создания объекта, structкоторый пересекает несколько страниц, гарантируя, что адрес памяти свойства находится на странице, отличной от реальных элементов данных. Страница свойства помечена как недоступная, что гарантирует, что попытка получить доступ к свойству приведет к ошибке. Затем обработчик ошибок выясняет, какой доступ к свойству вызвал segfault, и вызывает соответствующую функцию для вычисления значения свойства, которое сохраняется по адресу памяти свойства.

Обработчик ошибок также помечает страницу данных как доступную только для чтения, чтобы гарантировать, что вычисленное значение остается согласованным; когда вы в следующий раз попытаетесь выполнить запись в элемент данных, это вызовет ошибку сегмента, обработчик которой устанавливает страницу данных для чтения-записи и страницу свойств как отсутствие доступа (что указывает на необходимость пересчета).


15

Компьютерная версия в Common Lisp

Я изначально реализовал Come-From. Но этого было недостаточно.

Вдохновленный вычисленным 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.

Для каждого объявления прихода в tagbody он будет проверять на каждой метке, равна ли переменная прихода текущей метке, и, если это так, переходить к соответствующему объявлению прихода.

Greeter

(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)))

FizzBuzz

(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

"Авто-струны" в рубине

Код довольно прост:

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);
}

Разве это не нарушит возможности PHP, которых нет в C? Такие как heredocs. На самом деле C PP был довольно тесно связан с грамматикой C.
Джои

1
Я думаю, что препроцессор только лексизирует ввод, не пытаясь понять это. An <<<HEREDOC- это не более чем 3 смещения ниже или влево и идентификатор :-) Это, однако, сделает макрос-замену в строках heredoc.
Арно Ле Блан

Препроцессор C добавляет лишний мусор к выводу, поэтому ваш пример не будет работать должным образом
анонимный трус

1
grep -v ^#Whould исправить это. Я думаю, этого достаточно для этого вопроса :-)
Арно Ле Блан,

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это декоратор, который создает новую функцию, которая реализует охрану сопоставления с образцом . Условия для каждой «подфункции», заданной в каждой строке документации в строках, начинающихся с pipe ( |). Если все условия оцениваются верно, эта версия функции запускается. Функции проверяются по порядку, пока не будет найдено совпадение. В противном случае 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 сопоставление с образцом позволяет вам сказать f [a,b,c] = ..., что не только проверяет аргумент против предиката, но и связывает соответствующие переменные при успешном сопоставлении. Это все еще довольно круто, хотя.
Джои Адамс

D'ой! Спасибо за исправление этого! Я тоже думал о Haskell, уделяя особое внимание определению функции с двумя разными предикатами (то есть f (x:xs) = ...и f [] = ...). Каким-то образом я запутал охранников там, но именно там я взял |.
zbanks

Это не вызов для игры в гольф; Вы можете быть более многословным (и читабельным), если хотите! :)
ReyCharles


7

Таможенные операторы в Lua

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

@FireFly На самом деле, я думаю, что это все еще работает. Подсветка синтаксиса становится странной, хотя.
гордый haskeller

6

Sliceable List в C # (например, Python)

Мне всегда нравилась нотация питона и хотелось бы, чтобы она была доступна в 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, она все еще просто игнорируется :(
Рэй

6

Сделать C проще

Этот код позволяет вам писать программы на C, которые немного напоминают язык сценариев. Он содержит ключевые слова, такие как «var», «is», «string», «plus», «equal» и ряд других. Он работает через множество определений.

// 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 mashup ...
Beta Decay

Там нет практически никакого верхнего предела - с достаточно сложными #defines вы можете даже дать своему языку такие вещи, как обработка исключений и сборка мусора , сохраняя при этом фундаментальный уровень C под ним.
Леушенко

5

Tcl

Tcl не имеет do ... whileили do ... 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, считая байты от начала файла.
Люсер Дрог

4

Symbol#to_proc с аргументами в Ruby

Symbol#to_procВероятно, это один из моих любимых приемов написания действительно лаконичного кода на Ruby. Предположим, у вас есть

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

и вы хотите преобразовать содержимое numsи textв Floats и прописные слова, соответственно. Symbol#to_procпозволяет сократить код следующим образом:

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

к этому:

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

Потрясающие! Но что , если мы хотим поднять каждый элемент numsк - iй степени, или заменить каждое вхождение sс *в text? Есть ли способ сократить код, как это?

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

Увы, нет простого способа передать аргументы при использовании Symbol#to_proc. Я видел, что это было сделано несколькими способами, но, вероятно, два из самых умных и полезных включают в себя мартовское исправление Symbolкласса [ 1 , 2 ]. Я проиллюстрирую первый способ ниже.

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);
});

Это не простой foreach, но более интересный. Он проверяет список аргументов потребляющей функции. Вы можете пойти дальше с этим трюком и делать действительно классные вещи.
Джои Адамс

1
Я собирался на foreach в стиле Tcl. Я добавил немного другой подход, который больше похож на Tcl.
Вольфхаммер

2

Gotos в Хаскелл

Основная идея заключается в том, что gotos можно частично смоделировать, используя последний оператор в do-notations. например:

main = do
  loop:
  print 3
  goto loop

эквивалентно

main = do
  loop
loop = do
  print 3
  loop

поскольку выполнение будет переходить к последнему утверждению, оптимальным является выражение gotos.

потому что, как это сделано, gotos прыгает только тогда, когда они находятся doнепосредственно в блоке определения верхнего уровня. это на самом деле «вызвать х и игнорировать остальную часть увиденного лексически утверждений», а не «все x и игнорирование остальных утверждений», как настоящий goto.

самая большая проблема заключается в том, что, когда нет способа покинуть выполнение с середины действия ввода-вывода - даже 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

1

Python Goto

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 без специального использования тега script на странице HTML

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

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

Это хромает, да, я знаю. Длина: 99


@ user2509848: Эта тема не помечена кодом гольф.
Джои Адамс

То, что вы опубликовали, требует scriptпометки вокруг. Тогда где именно эта новая функция?
Манатворк

@JoeyAdams Ой, прости.
Hosch250
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.