Selbsthaltende Protokolle

16

Das Problem"

Definieren Sie eine Funktion log(oder einen anderen 3-Buchstaben-Namen), die beim Aufruf sowohl die Anweisung (als Quelle) als auch das erste Argument protokolliert / druckt / schreibt (was auch immer die Standardeinstellung für die betreffende Sprache ist). Mit anderen Worten:

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

Für alle praktischen Zwecke würde die Ausgabe i: 777ausreichen, aber in einigen Sprachen gibt es dafür sehr spezielle Reflektionsbibliotheken, und das wäre keine Herausforderung, weshalb die gesamte Anweisung ausgegeben werden sollte.

Inspiration

Die Inspiration dafür war, dass ich und ein anderer Programmierer darüber diskutierten, wie irritierend es ist, dass Sie oft (mit schlechten Debuggern) Dinge schreiben console.log("i:", i), als nächstes haben wir eine (ziemlich verrückte) Javascript-Lösung (nur Knoten) erstellt (sie gibt i: 777eher als die gesamte Zeile aus) Quelle), die überraschend lang war und mich an Codegolf erinnerte und mich fragen ließ, wie viel besser andere (insbesondere Code-Golf) Sprachen abschneiden würden.

Boni

-10% : Kein Lesen von Dateien (außerhalb des Compilers)

PS. Dies ist meine erste "Frage" hier, also zögern Sie nicht, auf Fehler hinzuweisen, die ich gemacht habe.

David Mulder
quelle
1
Willkommen bei CodeGolf.SE! Ich persönlich halte Ihre Frage für ziemlich anständig, aber es ist normalerweise besser, Fragen über die Sandbox zu stellen, um Unklarheiten usw. aufzulösen, bevor die Leute anfangen, an Antworten zu arbeiten.
Martin Ender
Thx und die nützliche @ Sandbox könnten hilfreich sein, um die Verwendung zu erklären help/on-topic(es wird erwähnt, aber ich fand es nicht wert, die Beschreibung dort zu überprüfen).
David Mulder
@ WolleVanillebärLutz: Natürlich ist es nicht so, hast du gesehen, dass jemand behauptet, das sei dann wahr?
David Mulder
Die Prämie gilt für TrungDQ (ich denke, seine Lösung ist einfach aus Codeperspektive (besser als unsere Lösung nur für Knoten) erstaunlich, unabhängig von der Länge). Ich muss jedoch 24 Stunden warten, bevor ich sie vergeben kann.
David Mulder

Antworten:

14

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

Beachten Sie, dass in C eine logFunktion nur für einen bestimmten Typ definiert werden kann. Daher akzeptiert diese log"Funktion" nur intArgumente.

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

Eine allgemeinere Lösung gibt an, wie das Argument zusätzlich zum Argument selbst gedruckt werden soll:

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

was würde als zB lg2("%s", "I'm a string");oder verwendet werden lg2("%f", 3.1415).

nneonneo
quelle
Ich denke nicht, dass die letzten Klammern xnotwendig sind.
user12205
@ace: Ich dachte, sie könnten gebraucht werden, wenn der Benutzer einige seltsame Zeichen in das Argument einfügt, aber nach Überlegung denke ich, dass Sie Recht haben. Ich werde sie entfernen.
Nneonneo
10

Python (65 - 10% = 58,5)

Dies setzt voraus, dass sich Ihr Code in einer Datei befindet (bei Aufruf im interaktiven Interpreter wird eine ungerade Ausgabe erzeugt):

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

Es wurde auf Python 2.7.6 getestet.

Beispiel:

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

log(foo())

Ausgänge

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
quelle
1
Nett! Ich muss sagen, das ist das verrückte Zeug, das mich als Programmierer interessiert (negativer Index für eine native Funktion: O): P macht sich auf den Weg, um ein paar Dokumente zu finden
David Mulder
9

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

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

So verwendet:

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

Ausgänge:

log(i) 777
log(i+j+1) 1111
mattnewport
quelle
Sie können 30 Zeichen entfernen und einen Einzeiler erstellen, wenn Sie ihn in C anstelle von C ++: schreiben. Dies #define log(x)printf("log(%s) %d\n",#x,x)funktioniert jedoch nur für Ganzzahlen.
user12205
@ace: dann funktioniert es nur für einen Typ. (Dies ist auch die von mir vorgeschlagene Lösung, siehe unten)
nneonneo
@nneonneo Ich hasse es, wenn ich vergessen habe, vor dem Posten eines Kommentars zu aktualisieren.
user12205
5

Rebol3 - 31,5 (35 - 10%)

Hier ist eine einfache Implementierung, die von @draegtun abgekürzt wurde und für Zahlen gut funktioniert:

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

Ausführen von Ausgaben:

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

Es kann bei 42,3 Zeichen (47 - 10%) viel flexibler sein (um die Form von Nicht-Nummern-Typen anzuzeigen )

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

Die Ausgabe:

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

Javascript (325)

Ich denke, das ist die logFunktion, die Sie suchen:

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

Verwendung

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

Ausgabe

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

Langer Code

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

Funktioniert nur, wenn das Skript in einem <script>Tag abgelegt ist, das im .htmlDokument abgelegt ist, da es eine Anforderung location.hrefzum Abrufen des Quellcodes sendet . JSfiddle, F12 Dev Tool Console, eingebettet.js Dateien funktionieren nicht, ich versuche, sie überall verfügbar zu machen ...

Jedenfalls ist diese Frage interessant.

TrungDQ
quelle
Ich bin etwas skeptisch, das ist Cross-Browser.
Farid Nouri Neshat
3

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

Ja, Makros! Dies ist eigentlich genau die Art von Sachen, für die sie sind.

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

Lesbare Version:

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

Beispiel:

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

Ausgänge:

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

Da das Addieren ein Methodenaufruf in Scala ist, wird die ausführliche Syntax wieder hinzugefügt, aber es ist ziemlich nah! In einigen anderen Fällen ist es auch etwas ausführlicher.

Joe K
quelle
Wow, das ist ziemlich interessant, wenn man die Funktion hinzufügt. So viel cooles Zeug zu lernen: D
David Mulder
2

Bash (21 - 10% = 18,9)

Dies:

alias log=echo;set -v

Dann verwenden logSie wie gewohnt echo:

log $((1+1))

oder

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

Diese Methode erledigt alles, was erforderlich ist. Als Bonus werden einige zusätzliche Informationen gedruckt, die jedoch nicht ausdrücklich verboten sind.

Thomas Baruchel
quelle
2

BASH

Argumente werden in BASH nicht mit "(...)" übergeben, daher lasse ich die Ausgabe von 'log ()' zu diesem Stil passen:

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

quelle
$((...))kann $[...]stattdessen sein, aber ich habe die Zeichen nicht gezählt, so dass es bis jetzt keine Rolle spielt.
2

Clojure

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

Homoikonizität hat ihre Vorteile!

Benutzen:

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

Mal sehen, was passiert mit 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__))
beharrlichpedantisch
quelle
Wenn Sie zitieren x, müssen Sie wirklich ein mittleres Gensym (dh x#) verwenden? Ich denke, Sie werden den Ausdruck nur einmal bewerten (übrigens bin ich kein Clojure-Experte)
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

Alternativ aber nicht den Regeln entsprechend

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

Tcl, 42,3 (47 - 10%)

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

Verwendung:

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 : kleine Verbesserung

Johannes Kuhn
quelle
0

Gemeines Lisp - 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)))))
  • Benannt , @weil logder Standard Logarithmusfunktion und standardmäßig gesperrt (zumindest auf SBCL). Außerdem @ist nur ein Zeichen lang.
  • Dient als eine prognVariable mit einer variablen Anzahl von Argumenten, wird jedoch auf die Standardausgabe gedruckt. In realen Anwendungen würde ich wahrscheinlichsignal eine Bedingung mit einem S-Ausdruck verwenden, anstatt eine durch Leerzeichen getrennte Ausgabe zu drucken.
  • Im Gegensatz zur vorhandenen Clojure-Lösung wird letztendlich der Wert des protokollierten Ausdrucks zurückgegeben, sodass er (@ x)verwendet werden kann, wann ximmer er verwendet wird.
  • Drucken verwendet prin1, die eine read-able Zeichenfolge ausgibt . Dies ist nützlich, wenn Sie versuchen, protokollierte Ausdrücke zu reproduzieren.
  • Behandelt alle möglichen Typen (siehe Antwort C)
  • Berücksichtigt mehrere Werte
  • Erzeugt keine unterschiedlichen Ausgaben (siehe Antwort von Scala)
  • Funktioniert aus einer Datei und aus REPL (siehe Pyhton-Antwort)
  • Benötigt keinen Browser / Interpreter-Trick (Python-Traceback, Javascript-Anforderung)

Beispielausgaben:

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

Und schließlich, wenn ich das Obige defmacroanmelde, habe ich die ungolfed Version:

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
Core-Dump
quelle
0

PHP 138

Sie können login PHP nicht neu deklarieren, ohne ein anderes Modul ( APD) zu verwenden. Ich habe es loggstattdessen verwendet und kann es logbei Bedarf mit einem Beispiel erneut einreichen . Das ist geringfügig, aber sündiger, denke ich, ist die Annahme, dass die Protokollfunktion in einer eigenen Zeile ist. Ich kann meine Antwort entsprechend den Kommentaren aktualisieren.

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

Beispielausgabe:

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
*/
Sieg
quelle
-2

JavaScript 55 53

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

Verwendung:

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

Ausgabe:

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

Sie MÜSSEN doppelte Anführungszeichen verwenden, "sonst funktioniert es nicht.

kitcar2000
quelle
Unabhängig davon, dass die Regeln bereits verbogen wurden, indem sie nicht dem von mir angegebenen Beispiel-Pseudocode folgten, besteht das größere Problem darin, dass dies nur dann funktioniert, wenn die Variablen im globalen Kontext definiert sind (ich weiß, dass der Bewertungskontext komplexer ist, aber Punkt steht)
David Mulder
Der Punkt der Herausforderung war, dass Sie keine Zeichenfolge übergeben ... -1
Türklinke
Es ging nicht darum log("i:", i)... Ich glaube nicht, dass es ohne 'oder "in js nicht möglich ist ... Sie können es mit verkleinern, console.log('log('+o+')'+eval(x))aber die Ausgabe
stimmt
2
Sie können es in einer einzigen Zeile machen, ich habe es in Node gemacht, wie? Indem Sie einen Fehler auslösen, den Stapel abrufen, die Datei lesen und die Zeile extrahieren. Ja, irgendwie verrückt: D. Es könnte auch möglich sein, zu verwenden arguments.callee.caller.toString(), aber ich konnte nicht herausfinden, welche Zeile welche ist, wenn Sie zwei Protokolle haben.
David Mulder