Registros autocontenidos

16

El problema"

Defina una función log(u otro nombre de 3 letras) que, cuando se llame, registrará / imprimirá / escribirá (lo que sea el valor predeterminado para el idioma en cuestión) tanto la instrucción (como fuente) como el primer argumento. En otras palabras:

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

Para todos los propósitos prácticos, la salida i: 777sería suficiente, pero en algunos idiomas hay bibliotecas de reflexión muy específicas para eso, y eso no sería un desafío, por lo que toda la instrucción debería salir.

Inspiración

La inspiración para esto fue para mí y otro programador que discutía cuán irritante es que a menudo (con depuradores incorrectos), escribes cosas como console.log("i:", i), a continuación, creamos una solución de JavaScript (bastante loca) (solo nodo) (genera i: 777más que la línea completa de fuente), que fue sorprendentemente largo y me recordó a codegolfing y me hizo preguntarme qué mejor les iría a otros idiomas (especialmente el golf de código).

Bonos

-10% : sin lectura de archivos (más allá del compilador)

PD. Esta es mi primera 'pregunta' aquí, así que siéntase libre de señalar cualquier error que haya cometido.

David Mulder
fuente
1
Bienvenido a CodeGolf.SE! Personalmente, creo que su pregunta es bastante decente, pero generalmente es una mejor idea ejecutar ideas de preguntas a través del sandbox para resolver ambigüedades, etc., antes de que las personas comiencen a trabajar en las respuestas.
Martin Ender
Thx y útil @ sandbox, podría ser bueno para explicar su uso help/on-topic(se menciona, pero no considero que valga la pena comprobar cómo se describió allí).
David Mulder
@ WolleVanillebärLutz: Por supuesto que no, ¿viste a alguien afirmar que eso era cierto?
David Mulder
La recompensa es para TrungDQ (creo que su solución es increíble solo desde la perspectiva del código (mejor que nuestra solución de solo nodo), independientemente de la longitud), aunque tengo que esperar 24 horas antes de poder otorgarla.
David Mulder

Respuestas:

14

C (40-10% = 36) (38-10% = 34.2)

Tenga en cuenta que, en C, una logfunción solo se puede definir para un tipo específico. Por lo tanto, esta log"función" solo toma intargumentos.

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

Una solución más general especifica cómo imprimir el argumento, además del argumento en sí:

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

que se usaría como, por ejemplo, lg2("%s", "I'm a string");o lg2("%f", 3.1415).

nneonneo
fuente
No creo que los corchetes finales xsean necesarios.
user12205
@ace: pensé que podrían ser necesarios si el usuario introduce algunos caracteres extraños en el argumento, pero después de reflexionar, creo que tienes razón. Los eliminaré
nneonneo
10

Python (65-10% = 58.5)

Esto supone que su código está en un archivo (produce una salida impar si se invoca en el intérprete interactivo):

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

Ha sido probado en Python 2.7.6.

Ejemplo:

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

log(foo())

salidas

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
fuente
1
¡Agradable! Tengo que decir que este es el tipo de cosas locas que me interesan como programador (índice negativo en una función nativa: O): P se pregunta para encontrar algunos documentos
David Mulder
9

C ++ 121 71 67-10% = 60.3

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

Usado así:

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

Salidas:

log(i) 777
log(i+j+1) 1111
Mattnewport
fuente
Puede eliminar 30 caracteres y crear una línea si lo escribe en C en lugar de C ++: #define log(x)printf("log(%s) %d\n",#x,x)pero eso solo funcionará con números enteros.
user12205
@ace: entonces solo funciona para un tipo. (Además, esta es la solución que propuse, ver más abajo)
nneonneo
@nneonneo Odio cuando olvidé actualizar antes de publicar un comentario.
user12205
5

Rebol3 - 31.5 (35 - 10%)

Aquí hay una implementación simple acortada de @draegtun que funciona bien para números:

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

Ejecutarlo produce:

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

Puede ser mucho más flexible (para mostrar la forma de tipos no numéricos) en 42.3 caracteres (47 - 10%)

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

La salida:

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

Javascript (325)

Creo que esta es la logfunción que estás buscando:

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>

Salida

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

Código largo

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

Solo funciona cuando el script se coloca dentro <script> etiqueta que se coloca en el .htmldocumento porque envía una solicitud location.hrefpara obtener el código fuente. JSfiddle, F12 Dev Tool Console, los .jsarchivos incrustados no funcionarán, estoy tratando de que esté disponible en todas partes ...

De todos modos, esta pregunta es interesante.

TrungDQ
fuente
Soy un poco escéptico, este es un navegador cruzado.
Farid Nouri Neshat
3

Scala - (221 - 10%) = 198.9

Yay macros! Este es en realidad exactamente el tipo de cosas para las que son.

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

Versión legible:

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

Ejemplo:

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

Salidas:

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

Como la adición es una llamada al método en Scala, agrega esa sintaxis detallada de nuevo, ¡pero está bastante cerca! También es un poco más detallado en algunos otros casos.

Joe K
fuente
Wow, es bastante interesante ver @ la adición de la función. Tantas cosas geniales para aprender: D
David Mulder
2

golpe (21-10% = 18.9)

Esta:

alias log=echo;set -v

Luego use logcomo usaría echo:

log $((1+1))

o

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

Este método hará todo lo que se requiera; Como beneficio adicional, también se imprimirá información adicional, pero ninguna regla explícita lo prohíbe.

Thomas Baruchel
fuente
2

GOLPETAZO

Los argumentos no se pasan usando "(...)" en BASH, así que dejo que la salida de 'log ()' se ajuste a ese estilo:

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

fuente
$((...))puede ser $[...]en su lugar, pero no conté los caracteres, por lo que no importa hasta ahora.
2

Clojure

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

¡La homoiconicidad tiene sus beneficios!

Usar:

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

Veamos qué pasa 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__))
persistentemente pedante
fuente
Si cita x, ¿realmente necesita usar un gensym intermedio (es decir x#)? Creo que solo evaluarás la expresión una vez (por cierto, no soy un experto en 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

Alternativamente, pero no cumple con las reglas

julia> @show log(x)
log(x) => 1.3862943611198906
gggg
fuente
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"

Editar : pequeña mejora

Johannes Kuhn
fuente
0

Lisp común: 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)))))
  • Nombrado @porque loges la función de logaritmo estándar y bloqueado por defecto (al menos en SBCL). Además, @solo tiene un personaje de largo.
  • Actúa como a progn, tomando un número variable de argumentos, pero imprime a la salida estándar. En aplicaciones reales, probablementesignal una condición con una expresión S en lugar de imprimir una salida separada por espacios.
  • Contrariamente a la solución Clojure existente, finalmente devolvemos el valor de la expresión registrada, de modo que (@ x)se pueda usar siempre que xse use.
  • Usos de impresión prin1, que readproducen una cadena habilitada. Esto es útil cuando se intenta reproducir expresiones registradas.
  • Maneja todos los tipos posibles (ver respuesta C)
  • Toma en cuenta valores múltiples
  • No produce diferentes salidas (ver respuesta de Scala)
  • Funciona desde un archivo y desde REPL (Ver respuesta de Pyhton)
  • No requiere truco de navegador / intérprete (rastreo de Python, solicitud de Javascript)

Resultados de muestra:

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

Y finalmente, si registro lo anterior defmacro, tengo la versión sin golf:

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
volcado de memoria
fuente
0

PHP 138

No puede volver loga declarar en PHP sin usar otro módulo ( APD), así que en su logglugar, puedo volver a enviarlo con un logejemplo si es necesario. Eso es menor, pero más pecaminoso, supongo, es que esto supone que la función de registro está en una línea por sí misma. Puedo actualizar mi respuesta según lo dictado por los comentarios.

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

salida de ejemplo:

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
*/
Victoria
fuente
-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")

Salida:

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

DEBE utilizar comillas dobles, de lo "contrario no funcionará.

kitcar2000
fuente
Independientemente de que ya esté doblando las reglas al no seguir el pseudo código de ejemplo que proporcioné, el problema más grande es que solo funciona si y solo si las variables se definen en el contexto global (sé que el contexto de evaluación de evaluación es más complejo que eso, pero el punto se mantiene)
David Mulder
El punto del desafío era que no pasabas una cuerda ... -1
Pomo de la puerta
El punto no estaba funcionando log("i:", i)... no creo que no se pueda hacer sin 'o "en js ... puedes hacerlo más pequeño usando console.log('log('+o+')'+eval(x))pero la salida no coincidirá con la línea de código (a quién le importa)
rafaelcastrocouto
2
Puedes hacerlo en una sola línea, lo hice en nodo, ¿cómo? Al lanzar un error, obtener la pila, leer el archivo y extraer la línea. Sí, un poco loco: D. Además, podría ser posible usar arguments.callee.caller.toString(), pero no pude averiguar qué línea es cuál cuando tienes dos registros.
David Mulder