Journaux autonomes

16

Le problème"

Définissez une fonction log(ou un autre nom à 3 lettres) qui, lorsqu'elle sera appelée, enregistrera / imprimera / écrira (quelle que soit la valeur par défaut pour la langue en question) à la fois l'instruction (en tant que source) et le premier argument. En d'autres termes:

i=777
j=333
log(i) //outputs: "log(i) 777"
log(i+j+1) //outputs: "log(i+j+1) 1111"

À toutes fins pratiques, la sortie i: 777serait suffisante, mais dans certaines langues, il existe des bibliothèques de réflexion très spécifiques pour cela, et ce ne serait pas un défi, donc l'instruction entière devrait être sortie.

Inspiration

L'inspiration pour cela était moi et un autre programmeur discutant à quel point il est irritant que souvent (avec de mauvais débogueurs), vous écrivez des choses comme console.log("i:", i), ensuite nous avons fait une solution (assez folle) javascript (nœud uniquement) (elle génère i: 777plutôt que la ligne entière de source) qui était étonnamment longue et m'a rappelé le codegolfing et m'a fait me demander à quel point les autres langues (en particulier le golf de code) s'en tireraient mieux.

Bonus

-10% : pas de lecture de fichier (au-delà du compilateur)

PS. C'est ma première «question» ici, alors n'hésitez pas à signaler toutes les erreurs que j'ai faites.

David Mulder
la source
1
Bienvenue sur CodeGolf.SE! Personnellement, je pense que votre question est assez décente, mais c'est généralement une meilleure idée d'exécuter des idées de questions dans le bac à sable pour résoudre les ambiguïtés, etc. avant que les gens commencent à travailler sur les réponses.
Martin Ender
Thx et utile @ sandbox, pourraient être utiles pour expliquer son utilisation help/on-topic(il est mentionné, mais je n'ai pas jugé utile de vérifier la façon dont il a été décrit ici).
David Mulder
@ WolleVanillebärLutz: Bien sûr que non, avez-vous vu quelqu'un prétendre que c'était vrai alors?
David Mulder
La prime est pour TrungDQ (je pense que sa solution est incroyable uniquement du point de vue du code (mieux que notre solution de nœud uniquement), quelle que soit la longueur), mais je dois attendre 24 heures avant de pouvoir l'attribuer.
David Mulder

Réponses:

14

C (40-10% = 36) (38-10% = 34,2)

Notez qu'en C, une logfonction ne peut être définie que pour un type spécifique. Par conséquent, cette log"fonction" ne prend que des intarguments.

#define log(x)printf("log("#x") %d",x)

Une solution plus générale spécifie comment imprimer l'argument, en plus de l'argument lui-même:

#define lg2(f,x)printf("lg2("#x") "f,x)

qui serait utilisé par exemple lg2("%s", "I'm a string");ou lg2("%f", 3.1415).

nneonneo
la source
Je ne pense pas que les dernières parenthèses xsoient nécessaires.
user12205
@ace: Je pensais qu'ils pourraient être nécessaires si l'utilisateur insère des caractères étranges dans l'argument, mais après réflexion, je pense que vous avez raison. Je vais les retirer.
nneonneo
10

Python (65-10% = 58,5)

Cela suppose que votre code se trouve dans un fichier (il produit une sortie étrange s'il est appelé dans l'interpréteur interactif):

import traceback as t
def log(x):print t.extract_stack()[-2][3],x

Il a été testé sur Python 2.7.6.

Exemple:

def foo():
    x = 1
    log(x)
    for i in xrange(10):
        log(x+i+1)
    return x

log(foo())

les sorties

log(x) 1
log(x+i+1) 2
log(x+i+1) 3
log(x+i+1) 4
log(x+i+1) 5
log(x+i+1) 6
log(x+i+1) 7
log(x+i+1) 8
log(x+i+1) 9
log(x+i+1) 10
log(x+i+1) 11
log(foo()) 1
nneonneo
la source
1
Agréable! Je dois dire que c'est le genre de trucs fous qui m'intéresse en tant que programmeur (indice négatif sur une fonction native: O): P se demande de trouver des documents
David Mulder
9

C ++ 121 71 67-10% = 60,3

#include<iostream>
#define log(x)std::cout<<"log("#x") "<<(x)<<"\n"

Utilisé comme ceci:

int main() {
    int i = 777;
    int j = 333;
    log(i);
    log(i+j+1);
}

Les sorties:

log(i) 777
log(i+j+1) 1111
mattnewport
la source
Vous pouvez supprimer 30 caractères et créer une ligne si vous l'écrivez en C au lieu de C ++:, #define log(x)printf("log(%s) %d\n",#x,x)mais cela ne fonctionnera qu'avec des entiers.
user12205
@ace: alors cela ne fonctionne que pour un seul type. (Aussi, c'est la solution que j'ai proposée, voir ci-dessous)
nneonneo
@nneonneo Je déteste quand j'ai oublié de rafraîchir avant de poster un commentaire.
user12205
5

Rebol3 - 31,5 (35 - 10%)

Voici une implémentation simple raccourcie de @draegtun qui fonctionne bien pour les nombres:

log: func[p][print[{log[}p{]}do p]]

Le lancer génère:

>> log: func[p][print[{log[}p{]}do p]]
>> i: 777
>> j: 333
>> log [i]
log[ 777 ] 777
>> log[i + j + 1]
log[ i + j + 1 ] 1111

Il peut être beaucoup plus flexible (pour afficher la forme de types non numériques) à 42,3 caractères (47 - 10%)

log: func[p][print[{log}mold p mold/only do p]]

Le résultat:

>> log: func[p] [print[{log}mold p mold/only do p]]
>> log [join "4" 4]
log [join "4" 4] "44"  ;; shows a string
>> log [1 + 2]
log [1 + 2] 3 
kealist
la source
4

Javascript (325)

Je pense que c'est la logfonction que vous recherchez:

function log(m){L=(new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];N=L.split(':')[1];C=parseInt(L.split(':')[2]);R=new XMLHttpRequest();R.open('GET',location.href,0);R.onload=function(){console.log(R.response.split('\n')[N-1].substr(C-1).split(';')[0]+' = '+m)};R.send()}

Usage

<script>
function log(m){L=(new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];N=L.split(':')[1];C=parseInt(L.split(':')[2]);R=new XMLHttpRequest();R.open('GET',location.href,0);R.onload=function(){console.log(R.response.split('\n')[N-1].substr(C-1).split(';')[0]+' = '+m)};R.send()}

function doSomething() {
  var a = 123; log(a); var b = "Hello, I am TrungDQ!"; log(b);
}
doSomething();
var message = "...or just do it out here";
log(message + "!");
</script>

Production

log(a) = 123
log(b) = Hello, I am TrungDQ!
log(message + "!") = ...or just do it out here!

Code long

<script>
function log(msg) {
  // Get the line number and offset of the line where is function is called
  var lineInfo = (new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];
  var lineNum = lineInfo.split(':')[1];
  var charOffset = parseInt(lineInfo.split(':')[2]);

  // Get the file source
  request = new XMLHttpRequest();
  request.open('GET', window.location.href, true);

  request.onload = function() {
    // Get file source code
    var response = request.responseText;
    // Get the `log` line
    var line = response.split('\n')[lineNum - 1];
    // Get the `log` statement
    var logStatement = line.substr(charOffset - 1).split(';')[0];
    // Print it
    console.log(logStatement + ' = ' + msg);
  };
  request.send();
}

function doSomething() {
  var a = 123; log(a); var b = "Hello, I am TrungDQ!"; log(b);
}
doSomething();
</script>

Fonctionne uniquement lorsque le script est placé dans la <script>balise qui est placée dans le .htmldocument car il envoie une demande location.hrefpour obtenir le code source. JSfiddle, F12 Dev Tool Console, les .jsfichiers intégrés ne fonctionneront pas, j'essaie de le rendre disponible partout ...

Quoi qu'il en soit, cette question est intéressante.

TrungDQ
la source
Je suis peu sceptique que ce soit des navigateurs croisés.
Farid Nouri Neshat
3

Scala - (221 - 10%) = 198,9

Ouais les macros! C'est en fait exactement le genre de choses pour lesquelles ils sont.

import language.experimental.macros
def log(p:Any)=macro l
def l(c:reflect.macros.Context)(p:c.Expr[Any])={import c.universe._;reify{println("log("+(c.Expr[String](Literal(Constant(show(p.tree)))).splice)+") "+p.splice)}}

Version lisible:

import language.experimental.macros
def log(p: Any) = macro l
def l(c: reflect.macros.Context)(p: c.Expr[Any]) = {
  import c.universe._
  val inputString = show(p.tree)
  val inputStringExpr = c.Expr[String](Literal(Constant(inputString)))
  reify {
    println("log(" + (inputStringExpr.splice) + ") " + p.splice)
  }
}

Exemple:

log(1)
val x = 3
log(x)
val y = 4
log(x+y)

Les sorties:

log(1) 1
log(x) 3
log(x.+(y)) 7

Étant donné que l'addition est un appel de méthode dans Scala, il ajoute cette syntaxe verbeuse, mais c'est assez proche! C'est aussi un peu plus verbeux dans quelques autres cas.

Joe K
la source
Wow, c'est assez intéressant de voir @ l'ajout de la fonction. Tellement de trucs cool à apprendre: D
David Mulder
2

bash (21 - 10% = 18,9)

Cette:

alias log=echo;set -v

Ensuite, utilisez logcomme vous utiliseriez echo:

log $((1+1))

ou

A=2
B=3
log $((A+B))

Cette méthode fera tout ce qui est nécessaire; en bonus, des informations supplémentaires seront également imprimées, mais aucune règle explicite ne l'interdit.

Thomas Baruchel
la source
2

FRAPPER

Les arguments ne sont pas passés en utilisant "(...)" dans BASH, donc je laisse la sortie de 'log ()' s'adapter à ce style:

$ log(){ echo "$FUNCNAME $@: $(($@))"; }
$ i=333
$ j=777
$ log i
log i: 333
$ log i+j+1
log i+j+1: 1111

la source
$((...))peut être à la $[...]place mais je n'ai pas compté les caractères, donc ça n'a pas d'importance jusqu'à présent.
2

Clojure

(defmacro log[x] `(let [x# ~x] (println "log("'~x")" x#)))

L'homoiconicité a ses avantages!

Utiliser:

(def i 777)
(def j 333)
(log i) ;Prints log( i ) 777
(log (+ i j 1)) ;Prints log( (+ i j 1) ) 1111

Voyons ce qui se passe avec macroexpand:

(macroexpand '(log (+ i j 1))) 
;; Prints the following: 
(let* [x__1__auto__ (+ i j 1)] (clojure.core/println "log(" (quote (+ i j 1)) ")" x__1__auto__))
persistantepédantique
la source
Si vous citez x, avez-vous vraiment besoin d'utiliser un gensym intermédiaire (ie. x#)? Je pense que vous n'évaluerez l'expression qu'une seule fois (btw, je ne suis pas un expert de Clojure)
coredump
2

Julia, 51 * 0,9 = 45,9

julia> x=4
4
julia> macro log(x) println("log($x) $(log(eval(x)))") end
julia> @log(x)
log(x) 1.3862943611198906

Alternativement, mais ne respectant pas les règles

julia> @show log(x)
log(x) => 1.3862943611198906
gggg
la source
2

Tcl, 42,3 (47 - 10%)

proc log c {puts [dict g [info fr -1] cmd]\ $c}

Usage:

set i 777
set j 333
log $i  ;#outputs: "log $i 777"
log [expr {$i+$j+1}] ;#outputs: "log [expr {$i+$j+1}] 1111"

Edit : petite amélioration

Johannes Kuhn
la source
0

Lisp commun - 119,7 (133-10%)

(defmacro @(&whole f &rest r)(let((g(gensym)))`(let((,g(multiple-value-list,@r)))(progn(format t"~s~{ ~a~}
"',f,g)(values-list,g)))))
  • Nommé @car logest la fonction de logarithme standard et verrouillé par défaut (au moins sur SBCL). De plus, il @ne contient qu'un seul caractère.
  • Agit comme un progn, prenant un nombre variable d'arguments, mais imprime sur la sortie standard. Dans les applications réelles, j'aurais probablement signalune condition avec une expression S au lieu d'imprimer une sortie séparée par un espace.
  • Contrairement à la solution Clojure existante, nous retournons finalement la valeur de l'expression consignée, de sorte qu'elle (@ x)peut être utilisée chaque fois qu'elle xest utilisée.
  • L'impression utilise prin1, qui readgénère une chaîne -able. Ceci est utile lorsque vous essayez de reproduire des expressions enregistrées.
  • Gère tous les types possibles (voir réponse C)
  • Prend en compte plusieurs valeurs
  • Ne produit pas de sorties différentes (voir la réponse de Scala)
  • Fonctionne à partir d'un fichier et de REPL (Voir la réponse Pyhton)
  • Ne nécessite pas de tour de navigateur / interprète (Python traceback, demande Javascript)

Exemples de sorties:

CL-USER>(@ (+ 3 2))   ; user input
(@ (+ 3 2)) 5         ; printed output
5                     ; result of expression

CL-USER> (@ (values 3 4))  ; input
(@ (VALUES 3 4)) 3 4       ; logging
3                          ; first value
4                          ; second value

CL-USER>(@ (round 3.4))
(@ (ROUND 3.4)) 3 0.4000001
3                          ; rounded value
0.4000001                  ; delta

Et enfin, si je me connecte ci-dessus defmacro, j'ai la version non golfée:

CL-USER> (@ (defmacro @(&whole f &rest r)(let((g(gensym)))`(let((,g(multiple-value-list,@r)))(progn(format t"~s~{ ~a~}
"',f,g)(values-list,g))))))
STYLE-WARNING: redefining COMMON-LISP-USER::@ in DEFMACRO
(@
 (DEFMACRO @ (&WHOLE F &REST R)
   (LET ((G (GENSYM)))
     `(LET ((,G (MULTIPLE-VALUE-LIST ,@R)))
        (PROGN
         (FORMAT T ,"~s~{ ~a~}
"
                 ',F ,G)
         (VALUES-LIST ,G)))))) @
@ ; actual result
coredump
la source
0

PHP 138

Vous ne pouvez pas redéclarer logen PHP sans utiliser un autre module ( APD) donc j'ai utilisé à la loggplace, je peux resoumettre avec logexemple si nécessaire. C'est mineur, mais plus pécheresse, je suppose, c'est que cela suppose que la fonction de journal est sur une ligne par elle-même. Je peux mettre à jour ma réponse en fonction des commentaires.

<?php function logg($v){$b=debug_backtrace()[0];$h=fopen($b['file'],"r");for($i=0;$i<$b['line']&&$l=fgets($h);$i++);echo trim($l)." $v";}

exemple de sortie:

for ($i=1; $i<10; $i++) {   
  $j=$i+1;
  $k=$j+1;
  logg($i+$j+$k);
  echo "\n";
}
/*
logg($i+$j+$k); 6
logg($i+$j+$k); 9
logg($i+$j+$k); 12
logg($i+$j+$k); 15
logg($i+$j+$k); 18
logg($i+$j+$k); 21
logg($i+$j+$k); 24
logg($i+$j+$k); 27
logg($i+$j+$k); 30
*/
La victoire
la source
-2

JavaScript 55 53

function log(x){console.log('log("'+x+'") '+eval(x))}

Usage:

var i = 777,
    j = 333;
log("i")
log("j")
log("12*4")
log("i*j-4")

Production:

log("i") 777
log("j") 333
log("12*4") 48
log("i*j-4") 258737

Vous DEVEZ utiliser des guillemets doubles "sinon cela ne fonctionnera pas.

kitcar2000
la source
Indépendamment du fait qu'il plie déjà les règles en ne suivant pas l'exemple de pseudo-code que j'ai fourni, le plus gros problème est qu'il ne fonctionne que si et seulement si les variables sont définies dans le contexte global (je sais que le contexte d'évaluation eval est plus complexe que cela, mais le point tient)
David Mulder
Le but du défi était que vous ne passiez pas de chaîne ... -1
Poignée de porte
Le log("i:", i)'"console.log('log('+o+')'+eval(x))
problème ne se posait
2
Vous pouvez le faire en une seule ligne, je l'ai fait en noeud, comment? En lançant une erreur, en récupérant la pile, en lisant le fichier et en extrayant la ligne. Oui, un peu fou: D. De plus, il pourrait être possible d'utiliser arguments.callee.caller.toString(), mais je n'ai pas pu déterminer quelle ligne est laquelle lorsque vous avez deux journaux.
David Mulder