Самосодержащие журналы

16

Проблема"

Определите функцию log(или другое трехбуквенное имя), которая при вызове будет регистрировать / печатать / записывать (независимо от того, что по умолчанию для рассматриваемого языка) как инструкцию (как источник), так и первый аргумент. Другими словами:

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а не всю строку source), который был на удивление длинным и напомнил мне о Codegolfing и заставил меня задаться вопросом, насколько лучше другие (особенно Code-Golf) языки будут жить.

Бонусы

-10% : нет чтения файлов (кроме компилятора)

PS. Это мой первый «вопрос», поэтому не стесняйтесь указывать на любые ошибки, которые я допустил.

Дэвид Малдер
источник
1
Добро пожаловать в CodeGolf.SE! Лично я думаю, что ваш вопрос довольно приличный, но обычно лучше пробовать идеи вопроса через «песочницу», чтобы разрешить неясности и т.д., прежде чем люди начнут работать над ответами.
Мартин Эндер
Спасибо и полезная песочница @, может быть полезно объяснить, как она используется help/on-topic(упоминается, но я не считаю, что стоит проверить, как это там описано).
Дэвид Малдер
@ WolleVanillebärLutz: Конечно, нет, вы видели, чтобы кто-нибудь утверждал, что это правда?
Дэвид Малдер
Награда за TrungDQ (я думаю, что его решение просто великолепно с точки зрения кода (лучше, чем решение только для наших узлов), независимо от длины), хотя мне придется подождать 24 часа, прежде чем я смогу его наградить.
Дэвид Малдер

Ответы:

14

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

nneonneo
источник
Я не думаю, что заключительные скобки вокруг 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
nneonneo
источник
1
Ницца! Должен сказать, что это тот тип сумасшедших вещей, которые интересуют меня как программиста (отрицательный индекс для нативной функции: O): P удивляется, найдя несколько документов
Дэвид Малдер
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
mattnewport
источник
Вы можете удалить 30 символов и сделать однострочник, если вы напишите его на C вместо C ++:, #define log(x)printf("log(%s) %d\n",#x,x)но это будет работать только с целыми числами.
user12205
@ace: тогда это работает только для одного типа. (Кроме того, это решение, которое я предложил, см. Ниже)
nneonneo
@nneonneo Я ненавижу это, когда я забыл обновить перед публикацией комментария.
user12205
5

Ребол3 - 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 
kealist
источник
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 Tool Console, встроенные .jsфайлы не будут работать, я пытаюсь сделать его доступным везде ...

Во всяком случае, этот вопрос интересен.

TrungDQ
источник
Я немного скептически отношусь к кросс-браузерам.
Фарид Нури Нешат
3

Скала - (221 - 10%) = 198,9

Yay макросы! На самом деле это именно то, для чего они нужны.

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
Дэвид Малдер
2

Баш (21 - 10% = 18,9)

Эта:

alias log=echo;set -v

Затем используйте так, logкак вы бы использовали echo:

log $((1+1))

или

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

Этот метод будет делать все, что требуется; в качестве бонуса, некоторая дополнительная информация будет также напечатана, но никакое явное правило не запрещает это.

Томас Барухель
источник
2

BASH

Аргументы не передаются с использованием «(...)» в 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__))
persistentlypedantic
источник
Если вы цитируете x, вам действительно нужно использовать промежуточный генсим (т.е. x#)? Я думаю, что вы будете оценивать выражение только один раз (кстати, я не эксперт по Clojure)
coredump
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
GGGG
источник
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-выражением вместо вывода вывода через пробел.
  • В отличие от существующего решения 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
CoreDump
источник
0

PHP 138

Вы не можете переопределить logв PHP без использования другого модуля ( APD), поэтому я использовал 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

Вы ДОЛЖНЫ использовать двойные кавычки, "иначе это не сработает.

kitcar2000
источник
Независимо от того, что он уже нарушает правила, не следуя приведенному мной примеру псевдокода, большая проблема заключается в том, что он работает только тогда и только тогда, когда переменные определены в глобальном контексте (я знаю, что контекст оценки eval более сложен, чем этот, но точка стоит)
Дэвид Малдер
Суть проблемы заключалась в том, что вы не пропустили строку ... -1
дверная ручка
Дело не в том log("i:", i)... Я не думаю, что это не может быть сделано без 'или "в JS ... Вы можете уменьшить его, используя, console.log('log('+o+')'+eval(x))но вывод не будет соответствовать строке кода (кого это волнует)
rafaelcastrocouto
2
Вы можете сделать это в одной строке, я сделал это в узле, как? Выкидывая ошибку, получая стек, читая файл и извлекая строку. Да, вроде сумасшедший: D. Кроме того, это может быть возможно с помощью arguments.callee.caller.toString(), но я не смог выяснить, какая линия, когда у вас есть два журнала.
Дэвид Малдер