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.


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


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

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

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 

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.


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.


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.


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

$((...))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__))

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

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


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

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

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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.