บันทึกที่มีตนเอง


16

ปัญหา"

กำหนดฟังก์ชั่นlog(หรือชื่อตัวอักษร 3 ตัวอื่น ๆ ) ซึ่งเมื่อเรียกว่าจะเข้าสู่ระบบ / พิมพ์ / เขียน (สิ่งที่เป็นค่าเริ่มต้นสำหรับภาษาที่เป็นปัญหา) ทั้งคำแนะนำ (เป็นแหล่งที่มา) และอาร์กิวเมนต์แรก ในคำอื่น ๆ :

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

สำหรับวัตถุประสงค์เชิงปฏิบัติทั้งหมดผลลัพธ์i: 777จะเพียงพอ แต่ในบางภาษามีไลบรารีการสะท้อนที่เฉพาะเจาะจงมากสำหรับสิ่งนั้นและนั่นจะไม่ท้าทายดังนั้นการสอนทั้งหมดควรถูกเอาท์พุท

แรงบันดาลใจ

แรงบันดาลใจสำหรับเรื่องนี้คือฉันและโปรแกรมเมอร์คนอื่นคุยกันว่ามันน่ารำคาญแค่ไหน (กับผู้ debuggers ที่ไม่ดี) คุณเขียนสิ่งต่าง ๆconsole.log("i:", i)ต่อไปเราได้สร้างจาวาสคริปต์ (บ้าๆ) โหนด (โหนดเท่านั้น) (เอาท์พุทi: 777มากกว่าทั้งบรรทัด แหล่งที่มา) ซึ่งยาวมากและทำให้ฉันนึกถึง codegolfing และทำให้ฉันสงสัยว่าภาษาอื่น ๆ

โบนัส

-10% : ไม่มีการอ่านไฟล์ (เกินกว่าคอมไพเลอร์)

PS นี่คือ 'คำถาม' แรกของฉันที่นี่ดังนั้นอย่าลังเลที่จะชี้ให้เห็นข้อผิดพลาดใด ๆ ที่ฉันทำ


1
ยินดีต้อนรับสู่ CodeGolf.SE! ฉันคิดว่าคำถามของคุณค่อนข้างดี แต่โดยทั่วไปแล้วมันเป็นความคิดที่ดีกว่าในการใช้ความคิดของคำถามผ่านทางsandboxเพื่อแก้ไขความคลุมเครือ ฯลฯ ก่อนที่ผู้คนจะเริ่มทำงานกับคำตอบ
Martin Ender

ขอบคุณและมีประโยชน์ @ sandbox อาจจะดีที่จะอธิบายการใช้งานhelp/on-topic(มันถูกกล่าวถึง แต่ฉันไม่คิดว่ามันคุ้มค่าในการตรวจสอบวิธีที่อธิบายไว้ที่นั่น)
David Mulder

@ WolleVanillebärLutz: ใช่แล้วคุณเห็นคนที่อ้างว่าเป็นจริงหรือไม่?
David Mulder

รางวัลสำหรับ TrungDQ (ฉันคิดว่าวิธีแก้ปัญหาของเขาน่าทึ่งมากจากมุมมองโค้ด (ดีกว่าวิธีแก้ปัญหาเฉพาะโหนดของเรา) โดยไม่คำนึงถึงความยาว) ต้องรอ 24 ชั่วโมงก่อนที่ฉันจะให้รางวัล
David Mulder

คำตอบ:


14

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

โปรดทราบว่าใน C logฟังก์ชันสามารถกำหนดได้เฉพาะกับชนิดที่ระบุเท่านั้น ดังนั้นlog"ฟังก์ชั่น" นี้ใช้เพียงintข้อโต้แย้ง

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

โซลูชันทั่วไปเพิ่มเติมระบุวิธีพิมพ์อาร์กิวเมนต์นอกเหนือจากอาร์กิวเมนต์เอง:

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

ซึ่งจะนำมาใช้เป็นเช่นหรือlg2("%s", "I'm a string");lg2("%f", 3.1415)


ฉันไม่คิดว่าxจำเป็นต้องใช้วงเล็บเหลี่ยมสุดท้าย
user12205

@ace: ฉันคิดว่าพวกเขาอาจจำเป็นถ้าผู้ใช้ใส่อักขระแปลก ๆ ไว้ในการโต้แย้ง แต่เมื่อคิดฉันคิดว่าคุณพูดถูก ฉันจะลบพวกเขา
nneonneo

10

Python (65 -10% = 58.5)

สิ่งนี้จะถือว่ารหัสของคุณอยู่ในไฟล์ (มันจะสร้างเอาต์พุตแปลก ๆ หากเรียกใช้ในล่ามแบบโต้ตอบ):

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

มันได้รับการทดสอบใน Python 2.7.6

ตัวอย่าง:

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

log(foo())

เอาท์พุท

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
ดี! ต้องบอกว่านี่คือสิ่งที่บ้าที่ฉันสนใจในฐานะโปรแกรมเมอร์ (ดัชนีเชิงลบในฟังก์ชั่นพื้นเมือง: O): P อยากออกไปหาเอกสารบางอย่าง
David Mulder

9

C ++ 121 71 67 -10% = 60.3

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

ใช้แบบนี้:

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

ขาออก:

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

คุณสามารถลบ 30 อักขระและสร้างหนึ่งซับถ้าคุณเขียนใน C แทน C ++: #define log(x)printf("log(%s) %d\n",#x,x)แต่นั่นจะทำงานเฉพาะจำนวนเต็ม
user12205

@ace: มันใช้ได้กับประเภทเดียวเท่านั้น (นี่เป็นวิธีที่ฉันเสนอดูด้านล่าง)
nneonneo

@nneonneo ฉันเกลียดเมื่อฉันลืมรีเฟรชก่อนโพสต์ความคิดเห็น
user12205

5

Rebol3 - 31.5 (35 - 10%)

นี่คือการใช้งานที่ง่ายแบบย่อจาก @draegtun ซึ่งทำงานได้ดีกับตัวเลข:

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

ใช้มันเอาท์พุท:

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

สามารถยืดหยุ่นได้มากขึ้น (สำหรับการแสดงรูปแบบที่ไม่ใช่ตัวเลข) ที่42.3 ตัวอักษร (47 - 10%)

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

ผลลัพธ์:

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

ฉันคิดว่านี่เป็นlogฟังก์ชั่นที่คุณกำลังมองหา:

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

การใช้

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

เอาท์พุต

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

รหัสยาว

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

ใช้ได้เฉพาะเมื่อวางสคริปต์ภายใน<script>แท็กซึ่งใส่ไว้ใน.htmlเอกสารเพราะจะส่งคำขอไปlocation.hrefยังรับซอร์สโค้ด JSfiddle, คอนโซลเครื่องมือ F12 Dev, ถูกฝัง.jsไฟล์ที่ไม่ทำงานฉันกำลังพยายามทำให้มันใช้ได้ทุกที่ ...

อย่างไรก็ตามคำถามนี้น่าสนใจ


ฉันสงสัยเล็กน้อยว่านี่คือเบราว์เซอร์ข้าม
Farid Nouri Neshat

3

สกาล่า - (221 - 10%) = 198.9

มาโครมาย! นี่เป็นประเภทของสิ่งที่พวกเขาใช้จริง

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

รุ่นที่อ่านได้:

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

ตัวอย่าง:

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

ขาออก:

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

เนื่องจากการเพิ่มเป็นการเรียกใช้เมธอดใน Scala จึงเพิ่มไวยากรณ์ verbose กลับคืนมา แต่ก็ใกล้เคียงกัน! นอกจากนี้ยังมีรายละเอียดเพิ่มเติมเล็กน้อยในอีกสองสามกรณี


ว้าวมันน่าสนใจมากที่เห็น @ การเพิ่มฟังก์ชั่น สิ่งดีๆมากมายที่ต้องเรียนรู้: D
David Mulder

2

bash (21 - 10% = 18.9)

นี้:

alias log=echo;set -v

จากนั้นใช้logอย่างที่คุณต้องการecho :

log $((1+1))

หรือ

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

วิธีนี้จะทำทุกอย่างที่จำเป็น เป็นโบนัสข้อมูลพิเศษบางอย่างจะถูกพิมพ์เช่นกัน แต่ไม่มีกฎที่ชัดเจนห้าม


2

ทุบตี

อาร์กิวเมนต์ไม่ถูกส่งผ่านโดยใช้ "(... )" ใน BASH ดังนั้นฉันจึงปล่อยให้ 'log ()' เข้ากับสไตล์นั้น:

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

$((...))สามารถ$[...]แทนได้ แต่ฉันไม่ได้นับตัวอักษรดังนั้นตอนนี้มันไม่สำคัญเลย

2

Clojure

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

Homoiconicity นั้นมีประโยชน์มากมาย!

ใช้:

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

มาดูกันว่าเกิดอะไรขึ้นกับ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__))

หากคุณอ้างxว่าคุณจำเป็นต้องใช้ Gensym ระดับกลางx#หรือไม่? ฉันคิดว่าคุณจะประเมินการแสดงออกเพียงครั้งเดียว (btw ฉันไม่ใช่ผู้เชี่ยวชาญ 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

อีกวิธีหนึ่ง แต่ไม่ตรงตามกฎ

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}

การใช้งาน:

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

แก้ไข : ปรับปรุงเล็กน้อย


0

เสียงกระเพื่อมสามัญ - 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)))))
  • ตั้งชื่อ@เพราะlogเป็นฟังก์ชันลอการิทึมมาตรฐานและล็อคโดยค่าเริ่มต้น (อย่างน้อยใน SBCL) นอกจากนี้@มีความยาวอักขระเพียงตัวเดียว
  • ทำหน้าที่เป็น a prognโดยรับอาร์กิวเมนต์จำนวนตัวแปร แต่พิมพ์ไปที่เอาต์พุตมาตรฐาน ในแอปพลิเคชันจริงฉันอาจจะsignalมีเงื่อนไขกับ S-expression แทนที่จะเป็นเอาท์พุทที่คั่นด้วยช่องว่างการพิมพ์
  • ตรงกันข้ามกับโซลูชัน Clojure ที่มีอยู่แล้วเราจะส่งคืนค่าของนิพจน์ที่บันทึกไว้ในที่สุดเพื่อให้(@ x)สามารถใช้ได้ทุกครั้งที่xใช้
  • การพิมพ์ที่ใช้prin1ซึ่งเป็นผลreadสตริงที่ใช้งานได้ สิ่งนี้มีประโยชน์เมื่อพยายามสร้างนิพจน์ที่บันทึกใหม่
  • จัดการประเภทที่เป็นไปได้ทั้งหมด (ดูคำตอบ C)
  • คำนึงถึงค่า mutliple
  • ไม่สร้างเอาต์พุตที่แตกต่างกัน (ดูคำตอบที่สกาล่า)
  • ทำงานได้จากไฟล์และจาก REPL (ดูคำตอบ Pyhton)
  • ไม่จำเป็นต้องใช้เคล็ดลับเบราว์เซอร์ / ล่าม (Python traceback, คำขอ Javascript)

ตัวอย่างผลลัพธ์:

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

และในที่สุดถ้าฉันบันทึกไว้ข้างต้นdefmacroฉันมีเวอร์ชันที่ไม่ดี

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

คุณไม่สามารถประกาศซ้ำlogใน PHP โดยไม่ใช้โมดูลอื่น ( APD) ดังนั้นฉันจึงใช้loggแทนฉันสามารถส่งlogตัวอย่างอีกครั้งหากจำเป็น นั่นเป็นเรื่องเล็กน้อย แต่ฉันคิดว่ามันเป็นบาปมากกว่านี้เพราะฟังก์ชั่นบันทึกนั้นอยู่บนบรรทัดเดียว ฉันสามารถอัปเดตคำตอบของฉันตามความคิดเห็น

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

เอาท์พุทตัวอย่าง:

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

การใช้งาน:

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

เอาท์พุท:

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

คุณต้องใช้เครื่องหมายคำพูดคู่"มิฉะนั้นจะไม่ทำงาน


โดยไม่คำนึงถึงการดัดกฎโดยไม่ทำตามตัวอย่างหลอกที่ฉันให้ไว้ปัญหาที่ใหญ่กว่าก็คือมันทำงานได้ก็ต่อเมื่อตัวแปรถูกกำหนดในบริบทของโลก (ฉันรู้ว่าบริบทการประเมิน eval มีความซับซ้อนมากกว่านั้น แต่จุดยืน)
David Mulder

ประเด็นของความท้าทายคือคุณไม่ต้องผ่านสาย ... -1
Doorknob

จุดไม่ได้ทำlog("i:", i)... ฉันไม่คิดว่ามันจะไม่สามารถทำได้โดยไม่ต้อง'หรือ"ใน js ... คุณสามารถทำให้เล็กลงโดยใช้console.log('log('+o+')'+eval(x))แต่ผลลัพธ์จะไม่ตรงกับรหัสบรรทัด (ใครสนใจ)
rafaelcastrocouto

2
คุณสามารถทำได้ในบรรทัดเดียวฉันทำมันในโหนดได้อย่างไร โดยการโยนข้อผิดพลาดรับกองอ่านไฟล์และแยกบรรทัด อืมบ้าแล้ว: D นอกจากนี้อาจเป็นไปได้ที่จะใช้arguments.callee.caller.toString()แต่ฉันไม่สามารถคิดได้ว่าบรรทัดไหนที่เมื่อคุณมีสองบันทึก
David Mulder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.