Registri autonomi


16

Il problema"

Definire una funzione log(o un altro nome di 3 lettere) che quando viene chiamato registrerà / stamperà / scriverà (qualunque sia il valore predefinito per la lingua in questione) sia l'istruzione (come sorgente) che il primo argomento. In altre parole:

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

Per tutti gli scopi pratici, l'output i: 777sarebbe sufficiente, ma in alcune lingue ci sono librerie di riflessione molto specifiche per questo, e ciò non sarebbe una sfida, quindi l'intera istruzione dovrebbe essere emessa.

Ispirazione

L'ispirazione per questo console.log("i:", i)siamo stati io e un altro programmatore a discutere di quanto sia irritante che spesso (con cattivi debugger), scrivi cose come , dopo abbiamo fatto una soluzione (piuttosto folle) javascript (solo nodo) (che genera i: 777piuttosto che l'intera linea di fonte) che è stato sorprendentemente lungo e mi ha ricordato il codegolfing e mi ha fatto chiedermi quanto sarebbero andate meglio le altre lingue (specialmente il golf di codice).

bonus

-10% : nessuna lettura di file (oltre al compilatore)

PS. Questa è la mia prima "domanda" qui, quindi sentiti libero di sottolineare tutti gli errori che ho fatto.


1
Benvenuto in CodeGolf.SE! Personalmente penso che la tua domanda sia abbastanza decente, ma di solito è un'idea migliore far passare le idee delle domande attraverso la sandbox per risolvere le ambiguità ecc. Prima che le persone inizino a lavorare sulle risposte.
Martin Ender,

Grazie e utile @ sandbox, potrebbe essere utile spiegarne l'uso help/on-topic(è menzionato, ma non ho ritenuto che valesse la pena di verificare il modo in cui è stato descritto lì).
David Mulder,

@ WolleVanillebärLutz: Certo che no, hai visto qualcuno affermare che fosse vero allora?
David Mulder,

La taglia è per TrungDQ (penso che la sua soluzione sia sorprendente solo dal punto di vista del codice (meglio della nostra soluzione a nodo unico), indipendentemente dalla lunghezza), devo aspettare 24 ore prima di poterlo assegnare.
David Mulder,

Risposte:


14

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

Si noti che, in C, una logfunzione può essere definita solo per un tipo specifico. Pertanto, questa log"funzione" accetta solo intargomenti.

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

Una soluzione più generale specifica come stampare l'argomento, oltre all'argomento stesso:

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

che sarebbe usato come eg lg2("%s", "I'm a string");o lg2("%f", 3.1415).


Non penso che le parentesi finali in giro xsiano necessarie.
user12205

@ace: ho pensato che potrebbero essere necessari se l'utente inserisce alcuni caratteri strani nell'argomento, ma a riflessione penso che tu abbia ragione. Li rimuoverò.
nneonneo,

10

Python (65-10% = 58,5)

Ciò presuppone che il codice sia in un file (produce output dispari se richiamato nell'interprete interattivo):

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

È stato testato su Python 2.7.6.

Esempio:

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

log(foo())

uscite

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

1
Bello! Devo dire che questo è il tipo di cose folli che mi interessano come programmatore (indice negativo su una funzione nativa: O): P si meraviglia di trovare alcuni documenti
David Mulder

9

C ++ 121 71 67 -10% = 60.3

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

Usato così:

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

Uscite:

log(i) 777
log(i+j+1) 1111

Puoi rimuovere 30 caratteri e creare una riga se lo scrivi in ​​C anziché C ++:, #define log(x)printf("log(%s) %d\n",#x,x)ma funzionerà solo con numeri interi.
user12205

@ace: quindi funziona solo per un tipo. (Inoltre, questa è la soluzione che ho proposto, vedi sotto)
nneonneo

@nneonneo Lo odio quando ho dimenticato di aggiornare prima di pubblicare un commento.
user12205

5

Rebol3 - 31.5 (35-10%)

Ecco una semplice implementazione abbreviata da @draegtun che funziona bene per i numeri:

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

Eseguendolo emette:

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

Può essere molto più flessibile (per visualizzare la forma di tipi non numerici) a 42.3 caratteri (47-10%)

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

Il risultato:

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

4

Javascript (325)

Penso che questa sia la logfunzione che stai cercando:

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

uso

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

Produzione

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

Codice lungo

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

Funziona solo quando lo script viene inserito all'interno del <script>tag che viene inserito nel .htmldocumento perché invia una richiesta location.hrefper ottenere il codice sorgente. JSfiddle, F12 Dev Tool Console, i .jsfile integrati non funzionano, sto cercando di renderlo disponibile ovunque ...

Comunque, questa domanda è interessante.


Sono un po 'scettico, questo è cross-browser.
Farid Nouri Neshat,

3

Scala - (221-10%) = 198.9

Yay macro! Questo è in realtà esattamente il tipo di cose per cui sono.

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

Versione leggibile:

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

Esempio:

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

Uscite:

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

Poiché l'aggiunta è un metodo chiamato in Scala, aggiunge quella sintassi dettagliata di nuovo, ma è abbastanza vicina! È anche un po 'più dettagliato in un paio di altri casi.


Wow, è abbastanza interessante vedere @ l'aggiunta della funzione. Tante cose interessanti da imparare: D
David Mulder,

2

bash (21-10% = 18.9)

Questo:

alias log=echo;set -v

Quindi usa logcome faresti con echo:

log $((1+1))

o

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

Questo metodo farà tutto ciò che è richiesto; come bonus, verranno anche stampate alcune informazioni extra, ma nessuna regola esplicita lo proibisce.


2

BASH

Gli argomenti non vengono passati usando "(...)" in BASH, quindi lascio che l'output di 'log ()' si adatti a quello stile:

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

$((...))può essere $[...]invece ma non ho contato i caratteri, quindi non importa fino ad ora.

2

Clojure

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

L'omoiconicità ha i suoi vantaggi!

Usare:

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

Vediamo cosa sta succedendo con 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__))

Se xcitate, avete davvero bisogno di usare un gensym intermedio (es. x#)? Penso che valuterai l'espressione solo una volta (a proposito, non sono un esperto di 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

In alternativa, ma non rispettando le regole

julia> @show log(x)
log(x) => 1.3862943611198906

2

Tcl, 42,3 (47-10%)

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

Uso:

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

Modifica : piccolo miglioramento


0

Lisp comune - 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)))))
  • Chiamata @perché logè la funzione di logaritmo standard e bloccata per impostazione predefinita (almeno su SBCL). Inoltre, @è lungo solo un personaggio.
  • Funziona come un progn, prendendo un numero variabile di argomenti, ma stampa sull'output standard. Nelle applicazioni reali, probabilmente avrei signaluna condizione con un'espressione S invece di stampare un output separato da spazio.
  • Contrariamente alla soluzione Clojure esistente, alla fine restituiamo il valore dell'espressione registrata, in modo che (@ x) possa essere utilizzato ogni volta che xviene utilizzato.
  • Usi di stampa prin1 , che genera una readstringa in grado. Ciò è utile quando si tenta di riprodurre espressioni registrate.
  • Gestisce tutti i tipi possibili (vedi risposta C)
  • Tiene conto dei valori multipli
  • Non produce output diversi (vedi risposta Scala)
  • Funziona da un file e da REPL (vedi risposta Pyhton)
  • Non richiede il trucco browser / interprete (traceback Python, richiesta Javascript)

Output di esempio:

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

E infine, se registro quanto sopra defmacro, ho la versione ungolfed:

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

0

PHP 138

Non puoi ripetere la dichiarazione login PHP senza usare un altro modulo ( APD), quindi ho usato logginvece, posso inviare nuovamente con l' logesempio se necessario. Questo è minore, ma più peccaminoso suppongo sia che questo presupponga che la funzione di registro sia su una linea da sola. Posso aggiornare la mia risposta come dettato dai commenti.

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

esempio di output:

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

-2

JavaScript 55 53

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

Uso:

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

Produzione:

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

DEVI usare le virgolette doppie, "altrimenti non funzionerà.


Indipendentemente dal fatto che abbia già piegato le regole non seguendo lo pseudo codice di esempio che ho fornito, il problema maggiore è che funziona solo se e solo se le variabili sono definite nel contesto globale (so che il contesto di valutazione di valutazione è più complesso di quello, ma il punto è valido)
David Mulder,

Il punto della sfida era che non si passa una stringa ... -1
Maniglia della porta

Il punto non stava funzionando log("i:", i)... Non credo che non si possa fare a meno 'o "in js ... puoi console.log('log('+o+')'+eval(x))
ridurlo

2
Puoi farlo in una sola riga, l'ho fatto nel nodo, come? Lanciando un errore, ottenendo lo stack, leggendo il file ed estraendo la riga. Sì, un po 'pazzo: D. Inoltre, potrebbe essere possibile utilizzare arguments.callee.caller.toString(), ma non sono stato in grado di capire quale linea è quale quando hai due registri.
David Mulder,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.