Додавання функції до мови програмування [закрито]


55

Ваше завдання - приєднати функцію до мови програмування, або шляхом впровадження дуже розумної бібліотеки, або шляхом обробки тексту введення та / або налаштування процесу компіляції.

Ідеї:

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

Правила:

  • Принесіть щось до столу. Не просто скажіть "Шаблон Haskell", щоб додати засоби метапрограмування до Haskell. Це не StackOverflow.
  • Вся реалізація повинна вміщуватися в одному екрані (не рахуючи приклад).
  • Не розміщуйте код хостингу на зовнішньому сайті спеціально для цього завдання.
  • Виграє найбільш вражаюча чи дивовижна функція.

Не хвилюйтесь щодо правильної реалізації функції на 100%. Далеко від цього! Основним завданням є з'ясування того, що ви хочете зробити, і порочне відрізання деталей, поки ваше планове завдання не стане можливим.

Приклад:

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

Початковий підхід:

Гаразд, я знаю, що хотів би скористатися libgc, щоб мої лямбда вирішили проблеми вгору та вниз по фунаргу. Я думаю, що перше, що мені потрібно зробити, - це написати / знайти аналізатор для мови програмування на C, тоді мені потрібно буде дізнатися все про систему типу C. Я повинен був би розібратися, як це зрозуміти, наскільки це стосується типів. Чи потрібно мені реалізувати умовиводи типу, або мені просто потрібно вимагати введення формального параметра, як задано? Що про всі ці божевільні риси в CI ще не знають?

Цілком зрозуміло, що правильно реалізувати лямбда в C було б величезним завданням. Забудьте про правильність! Спростити, спростити.

Краще:

Закрутіть вгору фунаргів, кому їх потрібно? Я міг би бути в змозі зробити що - то хитре з GNU Кассіопеяна вкладених функцій і заяву вираження . Я хотів продемонструвати дивовижну синтаксичну трансформацію на 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
Я думаю, що Кен Томпсон нас усіх переміг : 0 байтів коду.
dmckee

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

3
Не впевнений , якщо це кваліфікується, але я написав приклад продовжень в C . Хоча трохи більше, ніж скріншот.
luser droog

1
Дякую тому, хто поставив це питання; У мене є чудова ідея для подання.
Джонатан Ван Матре

2
Додайте лямбда на С ... ей, не дивіться на мене так.
Левшенко

Відповіді:


27

Синтаксис OOP в Haskell

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 ($).
швейцарський

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

1
@swish ви можете зберегти персонажа (та мозковий цикл), скориставшисьflip id
Шон Д

24

goto на JavaScript?

Першою моєю думкою був функціональний підхід - додати параметр до функції, щоб вказати, з чого слід починати виконання, використовуючи це з switchоператором та зовнішнім циклом, який неодноразово викликає функцію за власним повернутим значенням . На жаль, це виключатиме використання локальних змінних, оскільки вони втрачають свої значення з кожним goto.

Я міг би використовувати withоператор і переміщувати всі заяви змінної на початок функції, але повинен був бути кращий спосіб. Врешті-решт я прийшов до мене, щоб використовувати обробку винятків JavaScript . Насправді Джоел Спольський сказав: "Я вважаю, що винятки є не кращими, ніж" гото ... " - очевидно, ідеально підходить.

Ідея полягала в тому, щоб всередині функції поставити нескінченний цикл, що закінчується лише returnвисловлюванням або невиконаним винятком. Усі готи, розцінені як винятки, будуть потрапляти в цикл, щоб запобігти його припиненню. Ось результат такого підходу:

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щоб вискочити з будь-якої області, навіть функції ), це означатиме підтримку продовження.
Joey Adams

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
Я прокручував другий блок, і моя єдина думка була "... вниз у кролячій норі".
Soham Chowdhury

18

Проповідь у С

Ітерація масивів (працює для статичних масивів, а не тих, що надходять через покажчик)

//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

Властивості в С

Tomasz Wegrzanowski реалізував властивості в звичайній C, навмисно сегментуючи програму, коли доступ до властивості.

Об'єкт із "властивістю" встановлюється шляхом створення structсимволу, який перетинає кілька сторінок, гарантуючи, що адреса пам'яті властивості лежить на іншій сторінці, ніж у реальних членів даних. Сторінка ресурсу позначена як відсутність доступу, що гарантує, що спроба доступу до ресурсу спричинить сегментарне значення. Потім обробник помилок з'ясовує, який доступ до властивості спричинив segfault, і викликає відповідну функцію для обчислення значення властивості, яке зберігається за адресою пам'яті ресурсу.

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


15

Обчислені вихідні з Common Lisp

Я спочатку реалізував походження. Але це було недостатньо добре.

Надихнувшись обчисленим гото, я вирішив застосувати обчислювані вихідні дані.

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

Для кожного оголошення про вихід у тезі, воно перевірятиме на кожній мітці, чи змінна вихідного рівня дорівнює поточній мітці, і якщо так, перейдіть до відповідної заяви про вихід.

Зеленіша

(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

"Авто-струни" в 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

Ми можемо просто використовувати препроцесор С для цього завдання.

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? Такі, як гередоки. Afair C PP був досить щільно прив'язаний до граматики С.
Джої

1
Я думаю, що препроцесор лише використовує вхід, не намагаючись зрозуміти це. А <<<HEREDOCце не що інше, як 3 нижчі або ліві зсуви та ідентифікатор :-) Однак це зробить макрозаміщення в рядках гередока.
Арно Ле Блан

Препроцесор C додає додаткове сміття до виходу, тому ваш приклад не буде працювати так, як очікувалося
анонімний боягуз

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

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 це називається охоронцями , а не узгодженням шаблону. У Haskell співставлення шаблонів дозволяє вам сказати f [a,b,c] = ..., що не тільки тестує аргумент на предикат, але воно пов'язує відповідні змінні після успішного співпадіння. Це все ще досить круто.
Joey Adams

D'oy! Дякуємо, що виправили це! Я теж думав про Haskell, спеціально зосередившись на визначенні функції з двома різними предикатами (тобто f (x:xs) = ...і f [] = ...). Якимось чином я змусив охоронців туди, але звідки я взяв |.
zbanks

Це не кодове завдання для гольфу; Ви можете бути більш докладно (і читати), якщо хочете! :)
ReyCharles


7

Спеціальні оператори в Луа

Погс спритно зловживав перевантаженням оператора в 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

Список фрагментів в 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", "рівний" та кілька інших. Це працює через безліч визначень тверджень.

// 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 ...
бета-розпад

Верхньої межі для цього майже немає - маючи достатньо складний #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підрахунку байтів із початку файлу.
luser droog

4

Symbol#to_proc з аргументами в Рубі

Symbol#to_procце, мабуть, один з моїх улюблених трюків для написання дійсно лаконічного коду Ruby. Припустимо, у вас є

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

і ви хочете , щоб перетворити вміст numsі textпоплавців і заголовних слів, відповідно. 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);
});

Це не просто передбачення, але цікавіше. Він перевіряє список аргументів споживаючої функції. Ви можете піти далі з цим фокусом і зробити дійсно круті речі.
Joey Adams

1
Я збирався передрукувати стиль Tcl. Я додав дещо інший підхід, який більше схожий на Tcl.
вовчий молот

2

Готос в Хаскелл

основна ідея полягає в тому, що gotos можна частково моделювати за допомогою останнього твердження в do-нотаціях. наприклад:

main = do
  loop:
  print 3
  goto loop

еквівалентно

main = do
  loop
loop = do
  print 3
  loop

оскільки виконання перейде до останнього твердження, оптимально виразити gotos.

тому що, як це робиться, готос стрибає лише тоді, коли вони знаходяться безпосередньо на doблоці визначення верхнього рівня. це насправді "виклик х і ігнорування решти лексично викладених висловлювань", а не "всі х і ігнорування решти висловлювань", як справжній 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

Пітон Гото

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-сторінці

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.