Log berisi diri

16

Masalah"

Tetapkan fungsi log(atau nama 3 huruf lainnya) yang bila dipanggil akan mencatat / mencetak / menulis (apa pun default untuk bahasa yang bersangkutan) baik instruksi (sebagai sumber) maupun argumen pertama. Dengan kata lain:

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

Untuk semua tujuan praktis, hasilnya i: 777 akan cukup, tetapi dalam beberapa bahasa ada perpustakaan refleksi yang sangat spesifik untuk itu, dan itu tidak akan menjadi tantangan, sehingga seluruh instruksi harus dikeluarkan.

Inspirasi

Inspirasi untuk ini adalah saya dan programmer lain yang mendiskusikan betapa menjengkelkannya hal itu sering terjadi (dengan debugger buruk), Anda menulis hal-hal seperti console.log("i:", i), selanjutnya kami membuat solusi javascript (node ​​only) (cukup gila) (yang dihasilkan i: 777daripada seluruh jajaran source) yang ternyata sangat panjang dan mengingatkan saya pada codegolfing dan membuat saya bertanya-tanya berapa banyak bahasa lain (terutama golf code) yang lebih baik.

Bonus

-10% : Tidak ada pembacaan file (di luar kompiler)

PS. Ini adalah 'pertanyaan' pertama saya di sini, jadi silakan tunjukkan kesalahan yang saya buat.

David Mulder
sumber
1
Selamat datang di CodeGolf.SE! Saya pribadi berpikir pertanyaan Anda cukup baik, tetapi biasanya ide yang lebih baik untuk menjalankan ide pertanyaan melalui kotak pasir untuk menyelesaikan ambiguitas dll sebelum orang mulai mengerjakan jawaban.
Martin Ender
Terima kasih dan berguna @ sandbox, mungkin baik untuk menjelaskan penggunaannya help/on-topic(disebutkan, tapi saya tidak menganggapnya layak untuk memeriksa cara dijelaskan di sana).
David Mulder
@ WolleVanillebärLutz: Tentu saja tidak, apakah Anda melihat ada yang mengklaim itu benar?
David Mulder
Hadiahnya adalah untuk TrungDQ (saya pikir solusinya luar biasa hanya dari perspektif kode (lebih baik daripada solusi node kami saja), terlepas dari panjangnya), harus menunggu 24 jam sebelum saya dapat menghadiahkannya.
David Mulder

Jawaban:

14

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

Perhatikan bahwa, dalam C, logfungsi hanya dapat didefinisikan untuk jenis tertentu. Karena itu, log"fungsi" ini hanya membutuhkan intargumen.

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

Solusi yang lebih umum menentukan cara mencetak argumen, selain argumen itu sendiri:

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

yang akan digunakan sebagai contoh lg2("%s", "I'm a string");atau lg2("%f", 3.1415).

nneonneo
sumber
Saya tidak berpikir tanda kurung terakhir xdiperlukan.
user12205
@ace: Saya pikir mereka mungkin diperlukan jika pengguna memasukkan beberapa karakter aneh dalam argumen, tetapi setelah refleksi saya pikir Anda benar. Saya akan menghapusnya.
nneonneo
10

Python (65 -10% = 58.5)

Ini mengasumsikan kode Anda ada dalam file (menghasilkan output aneh jika dipanggil dalam interpreter interaktif):

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

Ini telah diuji pada Python 2.7.6.

Contoh:

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

log(foo())

output

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
sumber
1
Bagus! Bisa dikatakan, ini adalah jenis hal gila yang menarik minat saya sebagai seorang programmer (indeks negatif pada fungsi asli: O): P heran untuk menemukan beberapa dokumen
David Mulder
9

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

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

Digunakan seperti ini:

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

Output:

log(i) 777
log(i+j+1) 1111
mattnewport
sumber
Anda dapat menghapus 30 char dan membuat satu-liner jika Anda menulisnya dalam C bukan C ++:, #define log(x)printf("log(%s) %d\n",#x,x)tetapi itu hanya akan berfungsi sebagai bilangan bulat.
user12205
@ace: maka hanya berfungsi untuk satu jenis. (Juga, ini solusi yang saya usulkan, lihat di bawah)
nneonneo
@nneonneo Saya benci kalau saya lupa menyegarkan sebelum mengirim komentar.
user12205
5

Rebol3 - 31,5 (35 - 10%)

Berikut ini adalah implementasi sederhana yang disingkat dari @draegtun yang berfungsi baik untuk angka:

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

Menjalankannya menghasilkan:

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

Ini bisa menjadi jauh lebih fleksibel (untuk menampilkan bentuk tipe non-angka) di 42,3 karakter (47 - 10%)

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

Hasil:

>> 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 
kealis
sumber
4

Javascript (325)

Saya pikir ini adalah logfungsi yang Anda cari:

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

Pemakaian

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

Keluaran

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

Kode panjang

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

Hanya berfungsi ketika skrip dimasukkan ke dalam <script>tag yang dimasukkan ke dalam .htmldokumen karena skrip mengirim permintaan location.hrefuntuk mendapatkan kode sumber. JSfiddle, F12 Dev Tool Console, .jsfile yang disematkan tidak akan berfungsi, saya mencoba membuatnya tersedia di mana-mana ...

Bagaimanapun, pertanyaan ini menarik.

TrungDQ
sumber
Saya sedikit skeptis ini adalah browser silang.
Farid Nouri Neshat
3

Scala - (221 - 10%) = 198.9

Makro Yay! Ini sebenarnya jenis barang untuk mereka.

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 yang dapat dibaca:

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

Contoh:

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

Output:

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

Karena penjumlahan adalah pemanggilan metode dalam Scala, ia menambahkan sintaks verbose itu kembali, tetapi cukup dekat! Ini juga sedikit lebih bertele-tele dalam beberapa kasus lainnya.

Joe K.
sumber
Wow, itu cukup menarik untuk melihat @ penambahan fungsi. Banyak hal keren untuk dipelajari: D
David Mulder
2

bash (21 - 10% = 18,9)

Ini:

alias log=echo;set -v

Kemudian gunakan logseperti yang akan Anda gunakan echo:

log $((1+1))

atau

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

Metode ini akan melakukan semua yang diperlukan; sebagai bonus, beberapa informasi tambahan juga akan dicetak, tetapi tidak ada aturan eksplisit yang melarangnya.

Thomas Baruchel
sumber
2

PESTA

Argumen tidak diteruskan menggunakan "(...)" di BASH, jadi saya membiarkan keluaran 'log ()' cocok dengan gaya itu:

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

sumber
$((...))bisa $[...]saja tetapi saya tidak menghitung karakter, jadi tidak masalah sampai sekarang.
2

Clojure

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

Homoiconicity memiliki manfaatnya!

Menggunakan:

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

Mari kita lihat apa yang terjadi dengan 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__))
gigih terus-menerus
sumber
Jika Anda mengutip x, apakah Anda benar-benar perlu menggunakan gensym perantara (mis. x#)? Saya pikir Anda hanya akan mengevaluasi ekspresi sekali (btw, saya bukan ahli 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

Atau, tetapi tidak memenuhi aturan

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

Tcl, 42,3 (47 - 10%)

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

Pemakaian:

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

Sunting : peningkatan kecil

Johannes Kuhn
sumber
0

Gangguan Umum - 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)))))
  • Dinamakan @karenalog ini adalah fungsi logaritma standar dan dikunci secara default (setidaknya pada SBCL). Juga,@ hanya satu karakter.
  • Bertindak sebagai a progn, mengambil sejumlah variabel argumen, tetapi mencetak ke output standar. Dalam aplikasi nyata, saya mungkin akan melakukannyasignal suatu kondisi dengan ekspresi-S bukannya mencetak keluaran yang dipisahkan ruang.
  • Berlawanan dengan solusi Clojure yang ada, kami akhirnya mengembalikan nilai dari ekspresi yang dicatat, sehingga (@ x)dapat digunakan kapan sajax digunakan.
  • Penggunaan pencetakan prin1, yang menghasilkan aread string yang bisa digunakan. Ini berguna ketika mencoba mereproduksi ekspresi yang dicatat.
  • Menangani semua jenis yang mungkin (lihat jawaban C)
  • Memperhatikan nilai mutliple akun
  • Tidak menghasilkan output yang berbeda (lihat jawaban Scala)
  • Bekerja dari file dan dari REPL (Lihat jawaban Pyhton)
  • Tidak memerlukan trik peramban / juru bahasa (traceback Python, permintaan Javascript)

Output sampel:

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

Dan akhirnya, jika saya log di atas defmacro, saya memiliki versi yang tidak ungolfed:

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
coredump
sumber
0

PHP 138

Anda tidak dapat mendeklarasikan ulang logdalam PHP tanpa menggunakan modul lain ( APD) jadi saya gunakan loggsebagai gantinya, saya bisa mengirimkan kembali dengan logcontoh jika diperlukan. Itu kecil, tetapi lebih berdosa saya kira adalah ini menganggap fungsi log on a line dengan sendirinya. Saya dapat memperbarui jawaban saya sebagaimana ditentukan oleh komentar.

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

contoh output:

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
*/
Kemenangan
sumber
-2

JavaScript 55 53

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

Pemakaian:

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

Keluaran:

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

Anda HARUS menggunakan tanda kutip ganda "jika tidak maka tidak akan berhasil.

kitcar2000
sumber
Terlepas dari itu sudah menekuk aturan dengan tidak mengikuti contoh kode semu yang saya berikan, masalah yang lebih besar adalah bahwa itu hanya berfungsi jika dan hanya jika variabel didefinisikan dalam konteks global (saya tahu konteks evaluasi eval lebih kompleks dari itu, but point stand)
David Mulder
Inti dari tantangannya adalah Anda tidak melewatkan string ... -1
Doorknob
Intinya tidak melakukan log("i:", i) ... Saya tidak berpikir itu tidak dapat dilakukan tanpa 'atau "di js ... Anda dapat membuatnya lebih kecil menggunakan console.log('log('+o+')'+eval(x))tetapi output tidak akan cocok dengan baris kode (siapa yang peduli)
rafaelcastrocouto
2
Anda dapat melakukannya dalam satu baris, saya melakukannya dalam simpul, bagaimana? Dengan melempar kesalahan, mendapatkan tumpukan, membaca file dan mengekstrak baris. Yap, agak gila: D. Selain itu mungkin dimungkinkan menggunakan arguments.callee.caller.toString(), tetapi saya tidak dapat mengetahui baris mana yang ketika Anda memiliki dua log.
David Mulder