自包含日志


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就足够了,但是在某些语言中,有非常特定的反射库可以解决这个问题,因此应该输出整个指令。

灵感

这样做的灵感来自于我和另一个程序员,讨论的是它经常令人讨厌(使用不良的调试器),您编写诸如之类的东西console.log("i:", i),接下来我们制作了一个(非常疯狂的)javascript(仅节点)解决方案(它输出i: 777而不是整个代码行)源代码)的长度令人惊讶,它使我想起了代码高尔夫,让我想知道其他语言(尤其是代码高尔夫)的性能要好得多。

奖金

-10%:无文件读取(超出编译器)

PS。这是我的第一个“问题”,请随时指出我犯的任何错误。


1
欢迎来到CodeGolf.SE!我个人认为您的问题相当不错,但在人们开始研究答案之前,最好先通过沙盒运行问题思想以解决歧义等,这是一个更好的主意。
马丁·恩德

Thx和utility @ sandbox可能会很好地解释它的使用help/on-topic(已提及,但我认为不值得检查那里的描述方式)。
David Mulder 2014年

@WolleVanillebärLutz:当然不是,您看到有人声称那是真的吗?
David Mulder 2014年

赏金来自TrungDQ(我认为他的解决方案从代码角度来看是惊人的(比我们的仅节点解决方案更好,而不管它的长度如何),尽管必须等待24小时,然后我才能授予它。
David Mulder 2014年

Answers:


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

@ace:我认为如果用户在参数中输入一些奇数字符,可能需要使用它们,但是经过思考,我认为您是对的。我将其删除。
nneonneo

10

巨蟒(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 2014年

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

如果使用C而不是C ++:编写,则可以删除30个字符并形成一个单行代码#define log(x)printf("log(%s) %d\n",#x,x),但这仅适用于整数。
user12205 2014年

@ace:那么它仅适用于一种类型。(也是,这是我提出的解决方案,请参见下文)
nneonneo 2014年

@nneonneo我讨厌在发布评论之前忘记刷新的情况。
user12205 2014年

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开发人员工具控制台.js无法嵌入文件,我正在尝试使其随处可用...

无论如何,这个问题很有趣。


我有点怀疑这是跨浏览器。
Farid Nouri Neshat 2014年

3

Scala-(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中的方法调用,因此它又添加了冗长的语法,但是非常接近!在其他两种情况下,它也有些冗长。


哇,看到@该功能很有趣。有很多很酷的东西要学习:D
David Mulder

2

重击(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#)))

同质性有其好处!

使用方法:

(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#)?我认为您只会计算一次表达式(顺便说一句,我不是Clojure专家)
coredump 2014年

2

朱莉娅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

普通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)))))
  • 命名@是因为log是标准对数函数,默认情况下已锁定(至少在SBCL上)。而且,@只有一个字符长。
  • 用作progn,带有可变数量的参数,但打印到标准输出。在实际的应用程序中,我可能会signal使用S表达式而不是打印以空格分隔的输出。
  • 与现有的Clojure解决方案相反,我们最终返回记录的表达式的值,以便(@ x)可以随时x使用。
  • 打印使用prin1,输出一个read-able字符串。当尝试重现记录的表达式时,这很有用。
  • 处理所有可能的类型(请参阅C答案)
  • 考虑了多个值
  • 不会产生不同的输出(请参阅Scala答案)
  • 从文件和REPL进行工作(请参阅Pyhton答案)
  • 不需要浏览器/解释器技巧(Python追溯,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

138菲律宾比索

您不能log在不使用其他模块(APD)的情况下在PHP中重新声明,所以我logg改用了该log示例,如果需要,我可以重新提交示例。那是次要的,但我想更令人讨厌的是,这是假设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 2014年

挑战的关键是您不能传递任何字符串... -1
Doorknob

关键是没有做log("i:", i)……我认为没有它'"在js中都无法完成它……您可以使用使其变小,console.log('log('+o+')'+eval(x))但输出与代码行不匹配(谁在乎)
rafaelcastrocouto

2
您可以单行完成,我在节点中完成,如何?通过抛出错误,获取堆栈,读取文件并提取行。是的,有点疯狂:D。另外,也许可以使用arguments.callee.caller.toString(),但是当您有两个日志时,我无法确定哪一行是哪一行。
David Mulder 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.