Własne dzienniki

16

Problem"

Zdefiniuj funkcję log(lub inną trzyliterową nazwę), która po wywołaniu będzie logować / drukować / pisać (niezależnie od tego, jaki jest domyślny dla danego języka) zarówno instrukcję (jako źródło), jak i pierwszy argument. Innymi słowy:

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

Dla wszystkich praktycznych celów wynik i: 777byłby wystarczający, ale w niektórych językach istnieją do tego bardzo specyficzne biblioteki refleksji, co nie byłoby wyzwaniem, więc cała instrukcja powinna zostać wypisana.

Inspiracja

Inspiracją do tego byłem ja i inny programista dyskutujący o tym, jak irytujące jest to, że często (przy złych debuggerach) piszesz takie rzeczy console.log("i:", i), a następnie stworzyliśmy (dość zwariowane) rozwiązanie javascript (tylko węzeł) (generuje ono i: 777raczej niż całą linię źródło), która była zaskakująco długa i przypominała mi o kodzie golfowym i sprawiła, że ​​zastanawiałem się, o ile lepsze byłyby inne języki (zwłaszcza golfowe).

Bonusy

-10% : Brak odczytu pliku (poza kompilatorem)

PS. To jest moje pierwsze „pytanie” tutaj, więc możesz wskazać wszelkie błędy, które popełniłem.

David Mulder
źródło
1
Witamy w CodeGolf.SE! Osobiście uważam, że twoje pytanie jest całkiem przyzwoite, ale zwykle lepszym pomysłem jest uruchomienie pomysłów na pytania przez piaskownicę, aby rozwiązać dwuznaczności itp., Zanim ludzie zaczną pracować nad odpowiedziami.
Martin Ender
Dzięki i przydatne @ piaskownica, może warto wyjaśnić, na czym się posługuje help/on-topic(wspomniano, ale nie uważałem za warte sprawdzenia sposobu, w jaki tam został opisany).
David Mulder
@ WolleVanillebärLutz: Oczywiście, że nie, czy widziałeś, żeby ktoś twierdził, że to prawda?
David Mulder
Nagroda za TrungDQ (myślę, że jego rozwiązanie jest niesamowite tylko z punktu widzenia kodu (lepiej niż nasze rozwiązanie oparte tylko na węźle), niezależnie od długości), musi jednak czekać 24 godziny, zanim będę mógł je przyznać.
David Mulder

Odpowiedzi:

14

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

Zauważ, że w C logfunkcja może być zdefiniowana tylko dla określonego typu. Dlatego ta log„funkcja” przyjmuje tylko intargumenty.

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

Bardziej ogólne rozwiązanie określa, jak wydrukować argument, oprócz samego argumentu:

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

które byłyby wykorzystane jako np . lg2("%s", "I'm a string");lub lg2("%f", 3.1415).

nneonneo
źródło
Nie sądzę, aby ostatnie nawiasy xbyły konieczne.
user12205
@ace: Pomyślałem, że mogą być potrzebne, jeśli użytkownik doda kilka dziwnych znaków do argumentu, ale po refleksji myślę, że masz rację. Usunę je.
nneonneo
10

Python (65-10% = 58,5)

Zakłada się, że kod znajduje się w pliku (generuje nieparzyste dane wyjściowe, jeśli zostanie wywołany w interaktywnym tłumaczu):

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

Został przetestowany na Pythonie 2.7.6.

Przykład:

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

log(foo())

wyjścia

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
źródło
1
Ładny! Muszę powiedzieć, że jest to rodzaj szalonych rzeczy, które interesują mnie jako programistę (ujemny indeks funkcji natywnej: O): P zastanawia się nad znalezieniem niektórych dokumentów
David Mulder
9

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

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

Używany w ten sposób:

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

Wyjścia:

log(i) 777
log(i+j+1) 1111
mattnewport
źródło
Możesz usunąć 30 znaków i utworzyć jednowierszowy, jeśli napiszesz go w C zamiast w C ++:, #define log(x)printf("log(%s) %d\n",#x,x)ale zadziała to tylko z liczbami całkowitymi.
user12205
@ace: wtedy działa tylko dla jednego typu. (Także to jest rozwiązanie, które zaproponowałem, patrz poniżej)
nneonneo
@nneonneo Nienawidzę, gdy zapomniałem odświeżyć przed opublikowaniem komentarza.
user12205
5

Rebol 3 - 31,5 (35 - 10%)

Oto prosta implementacja skrócona z @draegtun, która działa dobrze dla liczb:

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

Uruchomienie go powoduje:

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

Może być znacznie bardziej elastyczny (do wyświetlania postaci typów nieliczbowych ) przy 42,3 znakach (47-10%)

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

Wyjście:

>> 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
źródło
4

JavaScript (325)

Myślę, że jest to logfunkcja, której szukasz:

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

Stosowanie

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

Wynik

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

Długi kod

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

Działa tylko wtedy, gdy skrypt jest umieszczony w <script>znaczniku, który jest umieszczony w .htmldokumencie, ponieważ wysyła żądanie location.hrefpobrania kodu źródłowego. JSfiddle, F12 Dev Tool Console, osadzone .jspliki nie będą działać, staram się udostępniać je wszędzie ...

W każdym razie to pytanie jest interesujące.

TrungDQ
źródło
Jestem trochę sceptyczny, to jest przeglądarka.
Farid Nouri Neshat
3

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

Tak, makra! To jest właśnie taki rodzaj rzeczy, do czego są przeznaczone.

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

Wersja do odczytu:

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

Przykład:

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

Wyjścia:

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

Ponieważ dodawanie jest wywołaniem metody w Scali, dodaje z powrotem tę pełną składnię, ale jest całkiem blisko! Jest to również trochę bardziej szczegółowe w kilku innych przypadkach.

Joe K
źródło
Wow, to całkiem interesujące zobaczyć @ dodanie funkcji. Tyle fajnych rzeczy do nauczenia: D
David Mulder
2

uderzenie (21-10% = 18,9)

To:

alias log=echo;set -v

Następnie użyj logtak, jakbyś użył echo:

log $((1+1))

lub

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

Ta metoda zrobi wszystko, co jest wymagane; w ramach bonusu zostaną wydrukowane również dodatkowe informacje, ale nie ma wyraźnej zasady zabraniającej tego.

Thomas Baruchel
źródło
2

GRZMOTNĄĆ

Argumenty nie są przekazywane za pomocą „(...)” w języku BASH, więc pozwalam, aby dane wyjściowe „log ()” pasowały do ​​tego stylu:

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

źródło
$((...))można $[...]zamiast tego, ale nie policzyłem znaków, więc do tej pory nie ma to znaczenia.
2

Clojure

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

Homoiconicity ma swoje zalety!

Używać:

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

Zobaczmy, co się dzieje z 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__))
uporczywie uporczywy
źródło
Jeśli xcytujesz, czy naprawdę potrzebujesz pośredniego gensym (tj. x#)? Myślę, że ocenisz wyrażenie tylko raz (przy okazji, nie jestem ekspertem od 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

Alternatywnie, ale niespełniający zasad

julia> @show log(x)
log(x) => 1.3862943611198906
gggg
źródło
2

Tcl, 42,3 (47–10%)

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

Stosowanie:

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

Edycja : mała poprawka

Johannes Kuhn
źródło
0

Common 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)))))
  • Nazwany, @ponieważ logjest standardową funkcją logarytmiczną i domyślnie zablokowany (przynajmniej w SBCL). Również,@ ma tylko jedną postać.
  • Działa jako progn, biorąc zmienną liczbę argumentów, ale wypisuje na standardowe wyjście. W rzeczywistych aplikacjach prawdopodobnie użyłbym signalwarunku z wyrażeniem S zamiast wypisywać wyniki rozdzielone spacjami.
  • W przeciwieństwie do istniejącego rozwiązania Clojure, ostatecznie zwracamy wartość zarejestrowanego wyrażenia, więc (@ x) można było z niego korzystać przy każdym xużyciu.
  • Zastosowania drukowania prin1 , które readgenerują ciąg -able. Jest to przydatne podczas próby odtworzenia zarejestrowanych wyrażeń.
  • Obsługuje wszystkie możliwe typy (patrz odpowiedź C)
  • Uwzględnia wartości wielokrotne
  • Nie wytwarza różnych wyników (patrz odpowiedź Scali)
  • Działa z pliku iz REPL (patrz odpowiedź Pyhton)
  • Nie wymaga sztuczki przeglądarki / interpretera (traceback w Pythonie, żądanie Javascript)

Przykładowe wyniki:

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

I wreszcie, jeśli defmacrozaloguję powyższe , mam wersję bez golfa:

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
rdzeń rdzeniowy
źródło
0

PHP 138

Nie można ponownie ustawić logjęzyka w PHP bez użycia innego modułu ( APD), więc użyłem go loggzamiast tego, w lograzie potrzeby mogę przesłać przykład. To niewielkie, ale bardziej grzeszne wydaje się, że zakłada to, że funkcja dziennika sama w sobie znajduje się w linii. Mogę zaktualizować swoją odpowiedź zgodnie z komentarzami.

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

przykładowe dane wyjściowe:

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
*/
Zwycięstwo
źródło
-2

JavaScript 55 53

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

Stosowanie:

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

Wynik:

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

MUSISZ użyć podwójnych cudzysłowów, w "przeciwnym razie to nie zadziała.

kitcar2000
źródło
Niezależnie od tego, że już naginałem reguły, nie podążając za przykładem pseudokodu, który podałem, większym problemem jest to, że działa tylko wtedy i tylko wtedy, gdy zmienne są zdefiniowane w kontekście globalnym (wiem, że ewaluacyjny kontekst oceny jest bardziej złożony, ale punkt stoi)
David Mulder
Wyzwanie polegało na tym, że nie przeszedłeś sznurka ... -1
Klamka
Nie chodziło o to log("i:", i)... Nie sądzę, że nie da się tego zrobić bez 'lub "w js ... można go zmniejszyć za pomocą, console.log('log('+o+')'+eval(x))ale wynik nie będzie pasował do linii kodu (kogo to obchodzi)
rafaelcastrocouto
2
Możesz to zrobić w jednym wierszu, zrobiłem to w węźle, jak? Zgłaszając błąd, pobierając stos, czytając plik i wyodrębniając wiersz. Tak, trochę szalony: D. Dodatkowo może być możliwe użycie arguments.callee.caller.toString(), ale nie byłem w stanie dowiedzieć się, która linia jest, kiedy masz dwa dzienniki.
David Mulder