Logs independentes


16

O problema"

Defina uma função log(ou outro nome de três letras) que, quando chamada, registrará / imprimirá / gravará (qualquer que seja o padrão para o idioma em questão), tanto a instrução (como fonte) quanto o primeiro argumento. Em outras palavras:

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

Para todos os propósitos práticos, o resultado i: 777seria suficiente, mas em algumas línguas existem bibliotecas de reflexão muito específicas para isso, e isso não seria um desafio, portanto, toda a instrução deve ser gerada.

Inspiração

A inspiração para isso foi eu e outro programador discutindo o quão irritante é que, muitas vezes (com depuradores ruins), você escreve coisas como console.log("i:", i), a seguir, criamos uma solução javascript (apenas louca) (somente nó) (ela gera, em i: 777vez de toda a linha de fonte), que foi surpreendentemente longa e me lembrou o codegolfing e me fez pensar em quanto melhor as outras línguas (especialmente o golfe por código) se sairiam.

Bónus

-10% : Nenhuma leitura de arquivo (além do compilador)

PS. Esta é a minha primeira 'pergunta' aqui, portanto, sinta-se à vontade para apontar os erros que cometi.


11
Bem-vindo ao CodeGolf.SE! Pessoalmente, acho que sua pergunta é bastante decente, mas geralmente é uma idéia melhor executá-la na sandbox para resolver ambiguidades etc. antes que as pessoas comecem a trabalhar nas respostas.
Martin Ender

Thx e úteis @ sandbox, podem ser bons para explicar seu uso help/on-topic(é mencionado, mas não achei que valesse a pena verificar a maneira como foi descrita lá).
David Mulder

@ WolleVanillebärLutz: Claro que não, você viu alguém afirmar que isso era verdade?
David Mulder

A recompensa é para o TrungDQ (acho que a solução dele é incrível apenas da perspectiva do código (melhor que a nossa solução apenas para nós), independentemente do tamanho), e preciso esperar 24 horas para que eu possa conceder.
David Mulder

Respostas:


14

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

Observe que, em C, uma logfunção pode ser definida apenas para um tipo específico. Portanto, essa log"função" recebe apenas intargumentos.

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

Uma solução mais geral especifica como imprimir o argumento, além do próprio argumento:

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

que seria usado como por exemplo lg2("%s", "I'm a string");ou lg2("%f", 3.1415).


Não acho que os colchetes finais xsejam necessários.
user12205

@ace: Eu pensei que eles poderiam ser necessários se o usuário colocar alguns caracteres estranhos no argumento, mas, pensando bem, acho que você está certo. Vou removê-los.
Nneonneo 21/03

10

Python (65 -10% = 58,5)

Isso pressupõe que seu código esteja em um arquivo (ele produz uma saída ímpar se invocado no intérprete interativo):

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

Foi testado no Python 2.7.6.

Exemplo:

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

log(foo())

saídas

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

11
Agradável! Tem a dizer, este é o tipo de coisas malucas que me interessa como um programador (índice negativo sobre a função nativa: o): P maravilhas fora de encontrar alguns docs
David Mulder

9

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

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

Usado assim:

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

Saídas:

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

Você pode remover 30 caracteres e criar uma linha, se você o escrever em C em vez de C ++:, #define log(x)printf("log(%s) %d\n",#x,x)mas isso funcionará apenas com números inteiros.
user12205

@ace: então só funciona para um tipo. (Além disso, esta é a solução que proposto, ver abaixo)
nneonneo

@nneonneo Eu odeio quando esqueci de atualizar antes de postar um comentário.
user12205

5

Rebol3 - 31,5 (35 - 10%)

Aqui está uma implementação simples abreviada de @draegtun que funciona bem para números:

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

Em execução, ele produz:

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

Pode ser muito mais flexível (para exibir a forma de tipos não numéricos) em 42,3 caracteres (47 - 10%)

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

A saída:

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

Eu acho que esta é a logfunção que você está procurando:

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>

Resultado

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

Código longo

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

Só funciona quando o script é colocado dentro da <script>tag, que é colocada no .htmldocumento porque envia uma solicitação location.hrefpara obter o código-fonte. JSfiddle, F12 Dev Tool Console, .jsarquivos incorporados não funcionarão, estou tentando disponibilizá-lo em qualquer lugar ...

Enfim, esta questão é interessante.


Estou um pouco cético em relação aos navegadores.
Farid Nouri Neshat 23/03

3

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

Yay macros! Na verdade, esse é exatamente o tipo de coisa para a qual eles servem.

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

Versão legível:

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

Exemplo:

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

Saídas:

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

Como a adição é uma chamada de método no Scala, ela adiciona novamente a sintaxe detalhada, mas é bem próxima! Também é um pouco mais detalhado em alguns outros casos.


Uau, é muito interessante ver @ a adição da função. Tanta coisa legal para aprender: D
David Mulder

2

bash (21 - 10% = 18,9)

Este:

alias log=echo;set -v

Então use logcomo você usaria echo:

log $((1+1))

ou

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

Este método fará tudo o que for necessário; como bônus, algumas informações extras também serão impressas, mas nenhuma regra explícita as proíbe.


2

BATER

Os argumentos não são passados ​​usando "(...)" no BASH, então deixo a saída de 'log ()' se encaixar nesse estilo:

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

$((...))pode ser, em $[...]vez disso, mas eu não contei os caracteres, por isso não importa até agora.

2

Clojure

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

A homoiconicidade tem seus benefícios!

Usar:

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

Vamos ver o que está acontecendo com 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 você citar x, você realmente precisa usar um gensym intermediário (ie. x#)? Eu acho que você avaliará a expressão apenas uma vez (btw, eu não sou especialista em 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

Como alternativa, mas não cumprindo as regras

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"

Edit : pequena melhoria


0

Lisp comum - 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)))))
  • Nomeado @porque logé a função de logaritmo padrão e bloqueado por padrão (pelo menos na SBCL). Além disso, @tem apenas um caractere.
  • Atua como a progn, obtendo um número variável de argumentos, mas imprime na saída padrão. Em aplicações reais, eu provavelmentesignal uma condição com uma expressão S em vez de imprimir uma saída separada por espaço.
  • Ao contrário da solução Clojure existente, finalmente retornamos o valor da expressão registrada, para que (@ x)possa ser usada sempre que xfor usada.
  • Utilizações de impressão prin1, que produz uma readcadeia de caracteres -able. Isso é útil ao tentar reproduzir expressões registradas.
  • Lida com todos os tipos possíveis (consulte a resposta C)
  • Leva em consideração valores múltiplos
  • Não produz resultados diferentes (consulte a resposta Scala)
  • Funciona a partir de um arquivo e do REPL (consulte a resposta do Pyhton)
  • Não requer truque de navegador / intérprete (rastreamento de Python, solicitação de Javascript)

Saídas de amostra:

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, finalmente, se eu registrar defmacroo item acima , tenho a versão não destruída:

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

Você não pode redefinir logno PHP sem usar outro módulo ( APD), então logg, em vez disso, posso reenviar com o logexemplo, se necessário. Isso é menor, mas mais pecador, eu acho, é que isso pressupõe que a função log esteja em uma linha por si só. Eu posso atualizar minha resposta como ditado pelos comentários.

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

saída de exemplo:

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

Resultado:

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

Você DEVE usar aspas duplas, "caso contrário não funcionará.


Independentemente de já ter dobrado as regras por não seguir o pseudocódigo de exemplo que forneci, o maior problema é que ele só funciona se e somente se as variáveis ​​forem definidas no contexto global (sei que o contexto da avaliação de avaliação é mais complexo que isso, mas o ponto está)
David Mulder

O objetivo do desafio era que você não passasse uma corda ... -1
Maçaneta da porta

O ponto não estava indo bem log("i:", i)... acho que não pode ser feito sem 'ou "em js ... você pode diminuir usando, console.log('log('+o+')'+eval(x))mas a saída não coincide com a linha de código (quem se importa)
rafaelcastrocouto

2
Você pode fazer isso em uma única linha, eu fiz no nó, como? Lançando um erro, obtendo a pilha, lendo o arquivo e extraindo a linha. Sim, meio louco: D. Além disso, pode ser possível usá-lo arguments.callee.caller.toString(), mas não consegui descobrir qual linha é qual quando você tem dois logs.
David Mulder
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.