Ajouter une fonctionnalité à un langage de programmation [fermé]

55

Votre tâche consiste à intégrer une fonctionnalité à un langage de programmation, soit en implémentant une bibliothèque très astucieuse, soit en traitant le texte saisi et / ou en peaufinant le processus de compilation.

Idées:

  • Ajoutez une présentation de type PHP entrelacée à C (par exemple <?c printf("Hello,"); ?> world!).
  • Ajoutez un opérateur de fusion nul à l'une de ces langues qui n'est pas C #.
  • Ajouter des macros à PHP.
  • Ajouter gotoà JavaScript.
  • Ajoutez un motif correspondant à la langue X.
  • Ajoutez la prise en charge des espaces de noms à une langue qui ne l’a pas.
  • Faites en sorte que C ressemble à PHP.
  • Faites ressembler Haskell à Pascal.
  • ... (n'hésitez pas à poster des idées dans la section commentaire)

Règles:

  • Apportez quelque chose à la table. Ne dites pas simplement "Template Haskell" pour ajouter des installations de métaprogrammation à Haskell. Ce n'est pas StackOverflow.
  • L’ensemble de la mise en œuvre doit tenir dans un seul écran (sans compter l’exemple).
  • N'hébergez pas de code sur un site externe spécifiquement pour cette tâche.
  • La fonctionnalité la plus impressionnante ou surprenante gagne.

Ne vous inquiétez pas pour implémenter la fonctionnalité à 100% correctement. Loin de là! Le principal défi consiste à déterminer ce que vous voulez faire et à supprimer vicieusement les détails jusqu'à ce que votre projet devienne réalisable.

Exemple:

Ajoutez un opérateur lambda au langage de programmation C.

Approche initiale:

Ok, je sais que je voudrais utiliser libgc afin que mes lambdas résolvent les problèmes de funarg ascendants et descendants. Je suppose que la première chose à faire est d’écrire / de trouver un analyseur syntaxique pour le langage de programmation C, puis d’apprendre tout sur le système de types de C. Il faudrait que je trouve un sens à la typographie. Aurais-je besoin d'implémenter l'inférence de type ou devrais-je simplement exiger que le paramètre formel soit typé comme étant donné? Qu'en est-il de toutes ces fonctionnalités folles de CI que vous ne connaissez pas encore?

Il est tout à fait clair que la mise en œuvre correcte de lambda en C serait une entreprise énorme. Oubliez l'exactitude! Simplifier, simplifier.

Mieux:

Amusez-vous! Qui a besoin d'eux? Je pourrais peut - être faire quelque chose délicate avec GNU C fonctions imbriquées et expressions de déclaration . Je voulais montrer une transformation syntaxique étonnante sur C avec un code laconique, mais je n’ai même pas besoin d’un analyseur. Cela peut attendre un autre jour.

Résultat (nécessite 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;
}

C'était facile, n'est-ce pas? J'ai même ajouté une mapmacro pour la rendre utile et jolie.

Joey Adams
la source
10
Je pense que Ken Thompson nous a tous battus : 0 octet de code.
dmckee
4
Je ne veux pas créer de réponse complète, mais j'ai ajouté des classes à GNU C , au cas où quelqu'un serait intéressé.
Richard J. Ross III
3
Je ne sais pas si c'est admissible, mais je l' ai écrit un exemple de continuations en C . Un peu plus qu'un écran, cependant.
luser droog
1
Merci à quiconque a ressuscité cette question; J'ai une excellente idée pour ma soumission.
Jonathan Van Matre
2
Ajoutez un lambda au C ... hé, ne me regardez pas comme ça.
Leushenko

Réponses:

27

Syntaxe de la POO dans Haskell

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

Les objets peuvent avoir des propriétés:

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

... et méthodes:

"Hello world!".take(5) -- "Hello"
"Hello world!".splitAt(2) -- ("He","llo world!")
"Hello world!".map(toUpper) -- "HELLO WORLD!"
lortabac
la source
2
Quelque part, j'ai vu cet opérateur écrit comme &et défini comme ceci (&) = flip ($).
Swish
6
@swish, je ne l'ai pas utilisé &parce que c'est l'opérateur unaire "adresse-de" (la mise en place de pointeurs en Haskell est laissée à un exercice pour le lecteur).
Lortabac
1
@swish vous pouvez enregistrer un personnage (et un cycle cérébral) en utilisantflip id
Sean D
24

goto en JavaScript?

Ma première pensée était une approche fonctionnelle - ajouter un paramètre à la fonction pour indiquer le début de l’exécution, en l’utilisant avec une switchinstruction et une boucle externe appelant à plusieurs reprises la fonction avec sa propre valeur de retour . Malheureusement, cela empêcherait l'utilisation de variables locales, car elles perdraient leurs valeurs à chaque goto.

Je pouvais utiliser une withinstruction et déplacer toutes les déclarations de variable au début de la fonction, mais il devait y avoir un meilleur moyen. Il m'est finalement arrivé d'utiliser la gestion des exceptions JavaScript . En fait, Joel Spolsky a déclaré: "Je considère que les exceptions ne valent pas mieux que" goto's ... " - de toute évidence un ajustement parfait.

L'idée était de placer une boucle infinie à l'intérieur d'une fonction, uniquement terminée par une returninstruction ou une exception non interceptée. Tous les gotos, traités comme des exceptions, seraient pris dans la boucle pour éviter sa terminaison. Voici le résultat de cette approche:

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

Vous pouvez l'utiliser comme ceci - même en mode strict ES5 - sauf dans Internet Explorer ( démo ):

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

[Internet Explorer, pour une raison quelconque, ne parvient pas à évaluer le code d’une fonction anonyme, il faudrait donc lui attribuer un nom (avant sa réécriture) et l’appeler avec ce nom. Bien sûr, cela enfreindrait probablement les règles du mode strict.]

Cela ne permet pas de sauter à une instruction située dans un bloc (jusqu'à ce que des constructions telles que le périphérique de Duff deviennent légales), mais nous pouvons en traiter (une autre fonction réécrite auto-exécutante), non?

Veuillez vous lever
la source
1
Sucré! Beau travail en gardant les choses simples. Une anecdote intéressante: si gotoimplémenté entièrement en JavaScript (là où vous pourriez utiliser gotopour sortir de n'importe quelle portée, même une fonction ), cela impliquerait une prise en charge des continuations.
Joey Adams
22

#define in Java

J'ai pensé qu'il serait amusant d'implémenter des macros en 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("."));
    }

}

Exemple d'utilisation (converti en code précédemment posté; faisons-le bizarre):

#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@[email protected]`r`&R`~&`r;
$%p@[email protected]`r`&Wr$t`r;
$%p@[email protected]$l`;
$%p@[email protected]$l`R`~&`r;
$%p@[email protected]$l`Wr$t`r;
$%p@[email protected]`pt$@n;
$%[email protected]~yL$st;
$%[email protected]@gg$ng.L`v`l;
$%[email protected]@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;
    _

_
Justin
la source
7
Je faisais défiler le deuxième bloc et ma seule pensée était "... dans le terrier du lapin".
Soham Chowdhury
18

Foreach en C

Itérer les tableaux (fonctionne pour les tableaux statiques, pas ceux reçus par un pointeur)

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

Pour le tester:

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

résultat:

num=10
num=20
num=30
str=Hello
str=World
str=Foreach
str=Test
Nucléaire
la source
17

Propriétés en C

Tomasz Wegrzanowski a implémenté les propriétés dans la plaine C, en commettant intentionnellement une erreur de segmentation avec le programme lors de l'accès à la propriété.

Un objet avec une "propriété" est créé en créant un élément structqui traverse plusieurs pages, en s'assurant que l'adresse mémoire de la propriété se trouve dans une page différente de celle des membres de données réels. La page de la propriété est marquée comme sans accès, ce qui garantit que toute tentative d'accès à la propriété provoquera un segfault. Un gestionnaire d'erreurs détermine ensuite quelle propriété l'accès a provoqué le segfault et appelle la fonction appropriée pour calculer la valeur de la propriété, qui est stockée à l'adresse de mémoire de la propriété.

Le gestionnaire d'erreurs marque également la page de données en lecture seule pour garantir la cohérence de la valeur calculée. lors de la prochaine tentative d'écriture dans un membre de données, un segfault est déclenché, son gestionnaire définissant la page de données en lecture-écriture et la page de propriétés en tant qu'absence d'accès (indiquant qu'il doit être recalculé).

Escargot mécanique
la source
15

Venu calculé dans Common Lisp

J'ai initialement implémenté come-from. Mais cela ne suffisait pas.

Inspiré par le calcul obtenu, j'ai décidé de mettre en œuvre le calcul en provenance de.

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

Exemples d'utilisation

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

Pour chaque déclaration de provenance dans le tagbody, il vérifie sur chaque étiquette si la variable de provenance est égale à l'étiquette actuelle et, le cas échéant, passe à la déclaration de provenance correspondante.

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")))
Erik Haliewicz
la source
14

"Auto-strings" en Ruby

Le code est assez simple:

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

Maintenant tu peux faire

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!
Poignée de porte
la source
14
wat
undergroundmonorail
13

Ajouter des macros à PHP

Nous pouvons simplement utiliser le préprocesseur C pour cette tâche.

Un script php:

<?php

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

function test() {
        ERROR(Oops);
}

Pipe-le bien cpp:

cpp < test.php

Résultat:

<?php

function test() {
 trigger_error("Oops", E_USER_ERROR);
}
Arnaud Le Blanc
la source
Cette rupture avec les fonctionnalités de PHP qui n'existent pas en C ne va-t-elle pas? Tels que Heredocs. Afair le C PP était assez étroitement lié à la grammaire de C.
Joey le
1
Je pense que le préprocesseur ne fait qu'exprimer l'entrée sans essayer de la comprendre. Un <<<HEREDOCn'est rien de plus que 3 inférieur ou gauche et un identifiant :-) Cela fera une macro-substitution dans les chaînes heredoc, cependant.
Arnaud Le Blanc le
Le préprocesseur C ajoute un contenu supplémentaire à la sortie, pour que votre exemple ne fonctionne pas comme prévu
un lâche anonyme
1
Un grep -v ^#whould résoudre ce problème. Je suppose que cela suffit pour cette question :-)
Arnaud Le Blanc
10

Gardes de correspondance de motifs en 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

Le corps de la fonction comporte 288 caractères.

Les modèles de correspondance de modèle vous permettent d'utiliser des fonctions complètement différentes en fonction des valeurs d'argument. Bien qu'il puisse être facilement imité avec une série d' ifénoncés, les gardes de correspondance de modèle peuvent aider à séparer des sections de code, et c'est une excellente excuse pour faire une métaprogrammation délirante.

pattern_matchest un décorateur qui crée une nouvelle fonction qui implémente des gardes de filtrage de motifs . Les conditions pour chaque "sous-fonction" données dans chaque docstring sur des lignes commençant par un pipe ( |). Si toutes les conditions sont évaluées de manière honnête, cette version de la fonction est exécutée. Les fonctions sont testées dans l'ordre jusqu'à ce qu'une correspondance soit trouvée. Sinon, Noneest retourné.

Un exemple aidera à clarifier:

@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
zbanks
la source
En Haskell, cela s'appelle des gardes , pas une correspondance de modèle. Dans Haskell, la correspondance de modèle vous permet de dire f [a,b,c] = ...que non seulement teste l'argument par rapport à un prédicat, mais qu'il lie les variables respectives en cas de correspondance correcte. C'est quand même assez cool, cependant.
Joey Adams
D'oy! Merci d'avoir corrigé ça! Je pensais aussi à Haskell, en me concentrant spécifiquement sur la définition d'une fonction avec deux prédicats différents (ie f (x:xs) = ...et f [] = ...). D'une certaine manière, j'ai convoqué les gardes là-bas, mais c'est de là que j'ai pris le |message.
Zbanks
Ce n'est pas un défi de code de golf; vous pouvez être plus bavard (et lisible) si vous voulez! :)
ReyCharles
7

Coroutine

Je ne peux pas prendre le crédit pour cela, alors je l'ai marqué CW.

Coroutines in C de Simon Tatham

st0le
la source
7

Opérateurs personnalisés à Lua

Pogs a intelligemment abusé de la surcharge des opérateurs à Lua afin de permettre la définition d’opérateurs infixes personnalisés. J'ai développé cette fonctionnalité pour prendre en charge la section d'opérateur (appliquer partiellement un opérateur avec l'un des opérandes) et appeler l'objet résultant comme s'il s'agissait d'une fonction.

---- 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
Luciole
la source
7

Chaînes multilignes en javascript

Dans cette syntaxe élaborée pour les chaînes multilignes, chaque chaîne multiligne sera précédée d' (function(){/*un, d'un nouveau trait et sera suivie d'un nouveau et de */}+'').split('\n').slice(1,-1).join('\n').

en utilisant cette syntaxe étonnante et intuitive, nous pouvons enfin utiliser des chaînes multilignes:

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

pour les personnes qui n'aiment pas notre syntaxe simple, nous avons un compilateur pour notre nouveau langage fabuleux:

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

le même exemple, dans la version en langage compilé:

var string = #{
THIS IS A MULTILINE STRING
HOORAY!!!
}#;
console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!
fier haskeller
la source
1
Pour une raison quelconque, je ne peux pas mettre */mes chaînes multilignes. C’est super gênant d’inclure des expressions rationnelles dans les chaînes!
FireFly
@FireFly En fait, je pense que cela fonctionne toujours. La mise en évidence de Syntex devient toutefois étrange.
fier haskeller
6

Liste Sliceable en C # (comme Python)

J'ai toujours apprécié la notation slice de python et je souhaite qu'elle soit disponible en C #

Usage:

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)

Code, loin de la preuve d'erreur:

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;
        }
    }
}
Moop
la source
J'ai demandé il y a longtemps que slicing soit inclus dans .NET, il est toujours simplement ignoré :(
Ray
6

Rendre C plus simple

Ce code vous permet d’écrire des programmes C qui ressemblent un peu plus à un langage de script. Il comporte des mots clés tels que "var", "est", "chaîne", "plus", "égal" et plusieurs autres. Cela fonctionne à travers de nombreuses déclarations.

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

Cela vous permet d'écrire du code comme:

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

Ce qui précède est étendu à:

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

Ce n’est probablement pas très utile, mais j’ai trouvé très intéressant de pouvoir créer un langage de programmation complet grâce à une série d’ #definealb.

icedvariables
la source
Cela ressemble à un mashup Javascript / Ruby ...
Beta Decay
Il n’ya pratiquement pas de limite supérieure à cela - avec des bases assez complexes #define, vous pouvez même donner à votre langage des éléments tels que la gestion des exceptions et la collecte des ordures tout en conservant le calque C fondamental en dessous.
Leushenko
5

Tcl

Tcl a pas do ... whileou do ... untilsi ...

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

Exemple:

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

uplevel exécute un script dans la portée des appelants.

Johannes Kuhn
la source
5

Aller en PostScript

Ma première pensée a été que je devrais me mêler de la pile exec, donc ce faux départ récupère l'opérateur de continuation pour arrêté depuis ghostscript (ou xpost).

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

Mais c'est plus simple que ça. Parce que file-position est la même pour tous les doublons du descripteur de fichier ( setfilepositionconsomme son argument, il s'agit donc de la seule sémantique utile pour cette fonction).

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

Cela imprime 5.

Il existe certaines limitations à ce qui précède. Le saut n'est pas immédiat, mais se produit lorsque if-body retourne au niveau supérieur et que l'interprète lit à nouveau dans le fichier (au lieu de lire dans le tableau qui contient if-body). À ce stade, le fichier a été repositionné et le «goto» prend effet.

luser droog
la source
Et ce ne sont que des définitions dans un dictionnaire, vous pouvez donc utiliser presque tous les types d'étiquettes.
luser droog
Vous pouvez également faire des sauts absolus encurrentfile <pos> setfileposition comptant les octets à partir du début du fichier.
luser droog
4

Symbol#to_proc avec des arguments en Ruby

Symbol#to_procest probablement l’un de mes trucs préférés pour écrire du code Ruby très succinct. Supposons que vous ayez

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

et vous voulez convertir le contenu de numset texten Floats et majuscules, respectivement. Symbol#to_procvous permet de raccourcir le code comme ceci:

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

pour ça:

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

Impressionnant! Mais si nous voulons relever tous les éléments de numsla iième puissance, ou de remplacer toutes les occurrences de savec *en text? Est-il possible de raccourcir un code comme celui-ci?

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

Hélas, il n'y a pas de moyen facile de passer des arguments lors de l'utilisation Symbol#to_proc. Je l'ai vu faire de multiples façons, mais deux des plus intelligentes et les plus utilisables impliquent probablement de patcher la Symbolclasse [ 1 , 2 ]. Je vais illustrer le premier moyen ci-dessous.

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

Maintenant, vous pouvez faire des choses comme:

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

JavaScript pour chaque

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

Sortie

Seattle, WA
New York, NY
Chicago, IL

Syntaxe alternative, plus proche de 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);
});
wolfhammer
la source
Ce n'est pas une simple affaire, mais c'est plus intéressant. Il inspecte la liste d'arguments de la fonction consommatrice. Vous pouvez aller plus loin avec cette astuce et faire des choses vraiment cool.
Joey Adams
1
J'allais pour un style Tcl pour chaque. J'ai ajouté une approche légèrement différente qui ressemble plus à Tcl.
Wolfhammer
2

Gotos dans Haskell

L'idée de base est que les gotos peuvent être partiellement simulés en utilisant le dernier énoncé de do-notations. par exemple:

main = do
  loop:
  print 3
  goto loop

est équivalent à

main = do
  loop
loop = do
  print 3
  loop

parce que l'exécution sautera à la dernière instruction, il est optimal d'exprimer gotos.

parce que, comme cela est fait, gotos saute seulement quand ils sont dodirectement au bloc d’une définition de niveau supérieur. c'est en fait "appeler x et ignorer le reste des instructions vues lexicalement " plutôt que "tout x et ignorer le reste des instructions", comme un vrai goto.

Le plus gros problème est que, quand il n'y a aucun moyen de quitter l'exécution du milieu d'une action IO, même returnsi ce n'est pas le cas; returnne fait rien quand ce n'est pas la dernière déclaration.

ceci surmonte ceci en capturant le reste des déclarations par un autre dobloc.

goto loop
print 3

devient

const loop $ do
print 3

la print 3déclaration est capturée par le dobloc et loopdevient la dernière déclaration.

cette transformation prend également en charge les variables présentes dans le champ des actions. Ceci est fait en se souvenant des variables qui sont dans la portée et en les passant dans les actions. par exemple:

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

cela se traduit simplement par:

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

quelques notes:

De plus, une return undefinedinstruction est ajoutée pour garantir que le dobloc de capture n'est pas vide.

parce que parfois, il y a une ambiguïté de type dans le dobloc de capture , au lieu de constnous utilisons asTypeOf, qui est identique à constmais requiert que ses deux paramètres aient le même type.

l'implémentation réelle (en 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
            }
        })
}

un exampe:

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

devient:

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

sortie:

a
c
fier haskeller
la source
Cela vaut la peine de préciser que, returndans Haskell, il s’agit d’une fonction régulière et qu’elle n’est pas liée au mot clé dans 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)

Usage

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

Exemple de cas de test

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

print "Asdf"

Exemple de sortie de cas de test

Asdf

Juste un peu de plaisir avec exec (). Peut générer une erreur de profondeur de récursivité maximale s'il n'est pas utilisé correctement.

Globby
la source
-2

// importer du javascript sans utiliser spécifiquement la balise script dans une page HTML

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

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

C'est nul ouais je sais. Longueur: 99

Mauro
la source
@ user2509848: Ce fil n'est pas étiqueté code golf.
Joey Adams
Ce que vous avez posté nécessite une scriptbalise autour. Alors où est exactement la nouvelle fonctionnalité?
manatwork
@ JoeyAdams Oups, désolé.
Hosch250