Adicionar um recurso a uma linguagem de programação [fechada]


55

Sua tarefa é aplicar um recurso a uma linguagem de programação, implementando uma biblioteca muito inteligente ou processando o texto de entrada e / ou aprimorando o processo de compilação.

Idéias:

  • Adicione apresentação em estilo PHP intercalada em C (por exemplo <?c printf("Hello,"); ?> world!).
  • Adicione um operador coalescente nulo a um desses idiomas que não é C #.
  • Adicione macros ao PHP.
  • Adicionar gotoao JavaScript.
  • Adicione um padrão correspondente ao idioma X.
  • Adicione suporte ao namespace a um idioma que não o possui.
  • Faça C parecer PHP.
  • Faça Haskell parecer Pascal.
  • ... (fique à vontade para postar ideias na seção de comentários)

Regras:

  • Traga algo para a mesa. Não basta dizer "Template Haskell" para adicionar recursos de metaprogramação ao Haskell. Isso não é StackOverflow.
  • Toda a implementação deve caber em uma tela (sem contar o exemplo).
  • Não hospede o código em um site externo especificamente para esta tarefa.
  • O recurso mais impressionante ou surpreendente vence.

Não se preocupe em implementar o recurso 100% corretamente. Longe disso! O principal desafio é descobrir o que você deseja fazer e cortar com crueldade os detalhes até que sua tarefa planejada se torne viável.

Exemplo:

Adicione um operador lambda à linguagem de programação C.

Abordagem inicial:

Ok, eu sei que gostaria de usar a libgc para que minhas lambdas resolvam os problemas de funarg para cima e para baixo. Eu acho que a primeira coisa que eu preciso fazer é escrever / encontrar um analisador para a linguagem de programação C, então eu precisaria aprender tudo sobre o sistema de tipos de C. Eu teria que descobrir como fazer sentido disso, tanto quanto os tipos. Eu precisaria implementar a inferência de tipo ou simplesmente exigiria que o parâmetro formal fosse digitado conforme fornecido? E todos esses recursos malucos no CI ainda não sabem?

Está bem claro que implementar corretamente o lambda em C seria uma tarefa enorme. Esqueça a correção! Simplifique, simplifique.

Melhor:

Dane-se funargs para cima, quem precisa deles? Eu poderia ser capaz de fazer algo complicado com o GNU C funções aninhadas e expressões declaração . Eu queria mostrar uma incrível transformação sintática em C com código hacker conciso, mas nem precisarei de um analisador para isso. Isso pode esperar por outro dia.

Resultado (requer 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;
}

Isso foi fácil, não foi? Até joguei uma mapmacro para torná-la útil e bonita.


10
Acho que Ken Thompson nos bateu : 0 bytes de código.
dmckee

4
Não quero criar uma resposta completa, mas adicionei classes ao GNU C , caso alguém esteja interessado.
Richard J. Ross III

3
Não sei se isso qualifica, mas eu escrevi um exemplo de continuações em C . Um pouco mais do que uma tela cheia, no entanto.
Luser droog

11
Meus agradecimentos a quem ressuscitou esta pergunta; Tenho uma excelente ideia para a minha apresentação.
Jonathan Van Matre

2
Adicione um lambda ao C ... ei, não me olhe assim.
Leushenko

Respostas:


27

Sintaxe OOP em Haskell

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

Objetos podem ter propriedades:

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

... e métodos:

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

2
Em algum lugar, vi esse operador escrito como &e definido assim (&) = flip ($).
swish

6
@swish Eu não usei &porque é o operador unário de 'endereço de' (a implementação de ponteiros em Haskell é deixada como um exercício para o leitor).
Lortabac

11
@swish você pode salvar um personagem (e um ciclo cerebral) usando #flip id
Sean D

24

goto em JavaScript?

Meu primeiro pensamento foi uma abordagem funcional - adicionar um parâmetro à função para indicar onde a execução deveria começar, usando isso com uma switchinstrução e um loop externo chamando repetidamente a função em seu próprio valor de retorno . Infelizmente, isso impediria o uso de variáveis ​​locais, pois elas perderiam seus valores a cada goto.

Eu poderia usar uma withinstrução e mover todas as declarações de variáveis ​​para o início da função, mas tinha que haver uma maneira melhor. Eventualmente, veio a mim usar o tratamento de exceções do JavaScript . De fato, Joel Spolsky disse: "Considero que as exceções não são melhores do que as" goto's ... " - obviamente um ajuste perfeito.

A idéia era colocar um loop infinito dentro de uma função, finalizada apenas por uma returndeclaração ou uma exceção não capturada. Todos os gotos, tratados como exceções, seriam capturados dentro do loop para impedir seu término. Aqui está o resultado dessa abordagem:

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

Você pode usá-lo assim - mesmo no modo estrito do ES5 - exceto no Internet Explorer ( demo ):

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

[O Internet Explorer, por algum motivo, falha na avaliação do código de uma função anônima; portanto, seria necessário dar um nome à função (antes de reescrever) e chamá-la usando esse nome. Obviamente, isso provavelmente violaria as regras do modo estrito.]

Isso não permite pular para uma instrução localizada dentro de um bloco (até que construções como o dispositivo de Duff se tornem legais), mas podemos lidar com isso (outra função reescrita auto-executável), certo?


11
Doce! Bom trabalho mantendo-o simples. Um pouco interessante: se gotofosse implementado completamente em JavaScript (para onde você poderia usar gotopara pular de qualquer escopo, até mesmo uma função ), isso implicaria suporte para continuações.
Joey Adams

22

#define em Java

Eu pensei que seria divertido implementar macros em 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("."));
    }

}

Uso de amostra (converte para código publicado anteriormente; vamos torná-lo estranho):

#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
Eu estava percorrendo o segundo quarteirão, e meu único pensamento era "... pela toca do coelho".
Soham Chowdhury

18

Foreach em C

Iterar matrizes (funciona para matrizes estáticas, não aquelas, recebidas pelo ponteiro)

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

Para testá-lo:

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

resultado:

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

17

Propriedades em C

Tomasz Wegrzanowski implementou propriedades em C simples, segmentando intencionalmente o programa quando a propriedade é acessada.

Um objeto com uma "propriedade" é configurado criando um structque atravessa várias páginas, garantindo que o endereço de memória da propriedade esteja em uma página diferente dos membros reais dos dados. A página da propriedade está marcada como sem acesso, garantindo que a tentativa de acessar a propriedade causará um segfault. Um manipulador de falhas descobre qual acesso à propriedade causou o segfault e chama a função apropriada para calcular o valor da propriedade, que é armazenado no endereço de memória da propriedade.

O manipulador de falhas também marca a página de dados como somente leitura para garantir que o valor calculado permaneça consistente; na próxima tentativa de gravar em um membro de dados, que dispara um segfault, cujo manipulador define a página de dados como leitura-gravação e a página de propriedades como sem acesso (indicando que ela precisa ser recalculada).


15

Origem computada no Common Lisp

Inicialmente, implementei o proveniente. Mas isso não foi bom o suficiente.

Inspirado pelo goto computado, decidi implementar o derivado computado.

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

Exemplos de uso

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

Para cada declaração proveniente do corpo da tag, ele verifica em cada rótulo se a variável proveniente é igual ao rótulo atual e, nesse caso, salta para a declaração proveniente correspondente.

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

"Auto-strings" em Ruby

O código é bastante simples:

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

Agora você pode fazer

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

Adicionar macros ao PHP

Podemos apenas usar o pré-processador C para esta tarefa.

Um script php:

<?php

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

function test() {
        ERROR(Oops);
}

Canalize-o através do cpp:

cpp < test.php

Resultado:

<?php

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

Isso não romperá com os recursos PHP que não existem em C? Como heredocs. Nesse caso, o C PP estava bastante ligado à gramática de C.
Joey

11
Eu acho que o pré-processador apenas lexica a entrada sem tentar fazer sentido. An <<<HEREDOCnada mais é do que três turnos inferiores ou à esquerda e um identificador :-) Isso fará uma substituição macro em cadeias de caracteres heredoc, no entanto.
Arnaud Le Blanc

O pré-processador C acrescenta lixo extra para a saída, para que o seu exemplo não funcionam como esperado
Covarde Anônimo

11
Um grep -v ^#conserto disso. Eu acho que isso é suficiente para esta pergunta :-)
Arnaud Le Blanc

10

Guardas de correspondência de padrões em 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

O corpo da função tem 288 caracteres.

Os protetores de correspondência de padrões permitem usar funções completamente diferentes, dependendo dos valores do argumento. Embora possa ser facilmente emulado com uma série de ifinstruções, os protetores de correspondência de padrões podem ajudar a separar seções do código, e é uma ótima desculpa para fazer uma metaprogramação maluca.

pattern_matché um decorador que cria uma nova função que implementa guardas de correspondência de padrões . As condições para cada "sub-função" dada em cada docstring nas linhas começando com um pipe ( |). Se todas as condições forem avaliadas com sinceridade, essa versão da função será executada. As funções são testadas em ordem até que uma correspondência seja encontrada. Caso contrário, Noneé retornado.

Um exemplo ajudará a esclarecer:

@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

Em Haskell, isso é chamado de guardas , não de correspondência de padrões. Em Haskell, a correspondência de padrões permite que você diga f [a,b,c] = ..., que não apenas testa o argumento em relação a um predicado, mas vincula as respectivas variáveis ​​após uma correspondência bem-sucedida. Isso ainda é bem legal, no entanto.
Joey Adams

D'oy! Obrigado por corrigir isso! Eu também estava pensando em Haskell, focando especificamente na definição de uma função com dois predicados diferentes (ie f (x:xs) = ...e f [] = ...). De alguma forma, convoquei guardas para lá, mas foi para lá que tirei |.
zbanks

Este não é um desafio de código de golfe; você pode ser mais detalhado (e legível), se quiser! :)
ReyCharles


7

Operadores personalizados em Lua

O Pogs abusou habilmente da sobrecarga de operadores em Lua para permitir a definição de operadores de infix personalizados. Expandi isso para dar suporte ao seccionamento do operador (aplicar parcialmente um operador com qualquer um dos operandos) e chamar o objeto resultante como se fosse uma função.

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

Cadeias de linhas múltiplas em javascript

nessa sintaxe elaborada para cadeias de (function(){/*linhas múltiplas, todas as cadeias de linhas múltiplas serão precedidas por uma nova linha e seguidas por uma nova linha e */}+'').split('\n').slice(1,-1).join('\n').

usando essa sintaxe incrível e intuitiva, podemos finalmente usar cadeias de linhas múltiplas:

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

para pessoas que não gostam da nossa sintaxe simples, temos um compilador para a nossa fabulosa nova linguagem:

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

o mesmo exemplo, na versão em idioma compilado:

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

11
Por alguma razão, não consigo colocar */minhas strings de múltiplas linhas. Isso é super irritante ao incluir regexps nas strings!
FireFly

@ FireFly Na verdade, acho que isso ainda funciona. O realce do síntex se torna estranho.
haskeller orgulhoso

6

Lista Sliceable em C # (como Python)

Eu sempre gostei da notação de fatia do python e gostaria que ela estivesse disponível em C #

Uso:

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)

Código, longe de ser à prova de erros:

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

I solicitado cortando há muito tempo para ser incluído no .NET, é ainda simplesmente ignoradas :(
Ray

6

Simplifique C

Esse código permite que você escreva programas em C que mais se assemelham a uma linguagem de script. Possui palavras-chave como 'var', 'is', 'string', 'plus', 'equal' e várias outras. Ele funciona através de várias instruções de definição.

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

Isso permite que você escreva códigos como:

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

O exposto acima é expandido para:

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

Provavelmente não é muito útil, mas achei bastante interessante que você pudesse criar essencialmente uma linguagem de programação inteira por meio de vários #defines.


Isso parece um mashup de Javascript / Ruby ...
Decay beta

Não há praticamente nenhum limite superior para isso - com #defines suficientemente complexos , você pode até dar ao seu idioma coisas como manipulação de exceção e coleta de lixo , mantendo a camada C fundamental por baixo.
Leushenko

5

Tcl

Tcl não tem mais do ... whileou do ... untilmenos ...

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

Exemplo:

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

uplevel executa um script no escopo dos chamadores.


5

Saltar em PostScript

Meu primeiro pensamento foi que eu teria que mexer com a pilha exec, portanto, esse falso início desenterra o operador de continuação para parar o ghostscript (ou xpost).

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

Mas, é mais simples que isso. Como a posição do arquivo é a mesma para todas as duplicatas do identificador de arquivo ( setfilepositionconsome seu argumento, essa é a única semântica útil para essa função).

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

Imprime 5.

Existem algumas limitações com o acima exposto. O salto não é imediato, mas acontece quando o corpo if retorna ao nível superior e o intérprete está novamente lendo o arquivo (em vez de ler a matriz que contém o corpo if). Nesse ponto, o arquivo foi reposicionado e o 'goto' entra em vigor.


E são apenas definições em um dicionário, para que você possa usar quase qualquer tipo para os rótulos.
Luser droog

Você também pode fazer saltos absolutos com a currentfile <pos> setfilepositioncontagem de bytes desde o início do arquivo.
Luser droog

4

Symbol#to_proc com argumentos em Ruby

Symbol#to_procé provavelmente um dos meus truques favoritos para escrever um código Ruby realmente sucinto. Suponha que você tenha

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

e você deseja converter o conteúdo de numse textpara flutuadores e palavras em maiúsculas, respectivamente. Symbol#to_procpermite que você reduza o código assim:

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

para isso:

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

Impressionante! Mas e se quisermos elevar todos os elementos numsà ipotência th ou substituir cada ocorrência de spor *in text? Existe alguma maneira de reduzir o código como este?

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

Infelizmente, não há maneira fácil de passar argumentos ao usar Symbol#to_proc. Eu já vi isso de várias maneiras, mas provavelmente duas das mais inteligentes e úteis envolvem a correção de macacos na Symbolclasse [ 1 , 2 ]. Ilustrarei o primeiro caminho abaixo.

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

Agora você pode fazer coisas como:

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

Resultado

Seattle, WA
New York, NY
Chicago, IL

Sintaxe alternativa, mais parecida com 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);
});

Esta não é uma tarefa simples, mas é mais interessante. Ele inspeciona a lista de argumentos da função consumidora. Você poderia ir além com esse truque e fazer coisas realmente legais.
Joey Adams

11
Eu estava indo para um forcl estilo Tcl. Eu adicionei uma abordagem um pouco diferente que é mais parecida com o Tcl.
wolfhammer

2

Gotos em Haskell

a idéia básica é que os gotos podem ser parcialmente simulados usando a última declaração em do-notations. por exemplo:

main = do
  loop:
  print 3
  goto loop

é equivalente a

main = do
  loop
loop = do
  print 3
  loop

como a execução pulará para a última instrução, é ideal expressar gotos.

porque da maneira que é feito, o gotos apenas salta quando está dodiretamente no bloco de uma definição de nível superior. na verdade, é "chame x e ignore o restante das instruções lexicamente vistas " em vez de "todo x e ignore o restante das instruções", como um verdadeiro goto.

o maior problema é que, quando não há como deixar a execução no meio de uma ação de IO - nem returnisso acontece; returnnão faz nada quando não é a última afirmação.

isso supera isso capturando o restante das instruções por outro dobloco.

goto loop
print 3

torna-se

const loop $ do
print 3

a print 3instrução é capturada pelo dobloco e loopse torna a última instrução.

essa transformação também suporta variáveis ​​presentes no escopo das ações. isso é feito lembrando as variáveis ​​que estão no escopo e passando-as para as ações. por exemplo:

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

isso simplesmente se traduz em:

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

algumas notas:

Além disso, uma return undefinedinstrução é adicionada para garantir que o dobloco de captura não esteja vazio.

porque às vezes há ambiguidade de tipo no dobloco de captura , em vez de constusarmos asTypeOf, que é o mesmo, constmas requer que ambos os parâmetros tenham o mesmo tipo.

a implementação real (em 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
            }
        })
}

um exemplo:

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

torna-se:

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

resultado:

a
c

Vale esclarecer que returnem Haskell é uma função regular e não relacionada à palavra-chave em 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)

Uso

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

Exemplo de Caso de Teste

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

print "Asdf"

Saída de exemplo de caso de teste

Asdf

Um pouco de diversão com exec (). Pode gerar um erro máximo de profundidade de recursão se não for usado corretamente.


-2

// importa javascript sem usar especificamente a tag de script em uma página HTML

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

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

É coxo, sim, eu sei. Comprimento: 99


@ user2509848: Este tópico não está codificado como código golf.
Joey Adams

O que você postou exige uma scriptmarcação. Então, onde exatamente está o novo recurso?
precisa saber é

@JoeyAdams Opa, desculpe.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.