LINUX.ORG.RU

присвоение внутри if

 


0

3

Зачем в языках программирования, например с Си и прочих, которые унаследовали его синтаксис есть возможность написать if (a=b). Вернет же всегда присвоение истину. Можете привести пример зачем это нужно? Попросили объяснить почему компилятор сам не понимает когда надо == а когда =. Не смог.

Перемещено JB из talks

Ответ на: комментарий от Begemoth

Мне сдаётся что этот костыль там нужен из-за странного поведения open. file = open(filename, attributes) куда логичней и общепринятей по-моему.

А <> по смыслу на разыменование указателя похоже в том куске.

Kalashnikov ★★★
()
Ответ на: комментарий от anonymous

Подобным образом можно создавать любые абстракции.

Для создания DSL конкатенативные языки всё равно гибче же.

Берешь да делаешь? Это же Лисп.

http://marijnhaverbeke.nl/monad.html
АБСТРАКТНО: реализовать монады вполне реально, но в CL — исключительно уродливым способом, это вам не хаскель.
---
И тем не менее:
http://docs.factorcode.org/content/vocab-monads.html

quantum-troll ★★★★★
()

Мое мнение, ТС, что лучше так не писать даже в while. Потом кому то твой код читать а то и править, пожалей его. Лучше напиши подлиннее но попроще а то я видел любителей писать даже так
(a = b + (c = d / 2) + c)
столько сточек экономится зато потом разбирать код адово и автора хочется повесить

bga_ ★★★★
()
Ответ на: комментарий от Kalashnikov

file = open(filename, attributes) куда привычнее для сишников и прочих ретроградов.

fixed.

kranky ★★★★★
()
Ответ на: комментарий от OxiD

Кажется если в первой строке будет 0, то все сломается.

Нет, просто присвоение вернёт тоже 0. Пофиксим этот баг:

open (FILE,'test.txt') or die $!;
kranky ★★★★★
()
Ответ на: комментарий от quantum-troll

Для создания DSL конкатенативные языки всё равно гибче же.

А для создания eDSL Лисп гибче.

это вам не хаскель.

Вот именно, зачем вообще нужны монады в императивном Лиспе?

И тем не менее:

http://common-lisp.net/project/cl-monad-macros/

anonymous
()
Ответ на: комментарий от belous_k_a

кстати, иногда так писать действительно удобно, когда под ифом выражение из over9k условий (если открыта первая вкладка и четвертая слева галочка включена, при этом приложение запущено в четный день недели, и этот день не священная суббота, и пользователь перешел на эту вкладку не сразу а со вкладки номер 3.... (итп) .... то триал закончился, System.exit).

stevejobs ★★★★☆
()
Ответ на: комментарий от quantum-troll

реализовать монады вполне реально, но в CL — исключительно уродливым способом, это вам не хаскель.

Какие задачи будет решать такая реализация? В хаскеле она решает задачи разделения кода на уровни (monadic stack), с гарантиями того, что код разных уровней не перемешается, возможно это потому, что типы (forall (m :: * -> *) (a :: *). m a) и (forall (a :: *). a) не сочетаются (это, в свою очередь, выразимо в языках с полиморфными типами и конструкторами типов, то есть в языках с ADT и системой типов λ₂ и выше). В CL они сочетаются. Вопрос нужно ставить не о maybe-like обёртках (зачем что-то оборачивать в динамическом языке? без статики - Nothing :: forall a. Maybe a = nil :: null <: t, Just anything :: forall a. Maybe a = anything :: t) и монадических интерфейсах к ним, а о необходимости введения таких обёрток и монадических интерфейсов в языках система типов которых беднее чем λ₂ (а сам язык, соответственно, содержит большее количество возможных программ - менее ограничен, менее консистентен).

Тут ещё надо откреститься от IO - у реализации может быть набор read/write примитивов с абстрактным типом IO и монадический интерфейс к IO. С оговорками, IO это просто ST поддерживаемый реализацией, а ST это, тривиально, функции вида a -> a и a -> b (ST a b = a -> (a, b)), монадический интерфейс к ST - return есть функция составляющая из двух значений кортеж, bind - обычная композиция функций. Короче, неинтересно. Делать «монады» в языке в котором это не имеет смысла просто чтобы было - тоже неинтересно. Интерес и предмет рассмотрения на тему нужно / не нужно может представлять именно использование monadic и прочих интерфейсов для построения стека приложения (и тут надо требовать статику).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Ничего интересного в первой библиотеке нет. Проба пера, не более. У меня были идеи сделать на основе cl-cont, но там возникли свои проблемы. А так, cl-cont имеет code walker, который даже перелопачивает циклы, а без этого неинтересно.

dave ★★★★★
()
Ответ на: комментарий от stevejobs

кстати, иногда так писать действительно удобно, когда под ифом выражение из over9k условий

Говнокод.

anonymous
()
Ответ на: комментарий от quantum-troll

Так надо метапрограммирование показать.

Покажи как

dosomething [ it print ] [ "error" print ] aif

развернуть во время компиляции в

[let dosomething :> it
  it [ it print ] [ "error" print ] if
]

Код примерный, так как Factor я пять минут знаю.

anonymous
()
Ответ на: комментарий от stevejobs

и какие ваши варианты сделать это не-говнокодом?

Самый простой вариант — дать этим условиям осмысленные имена, вынеся их в отдельные функции. Синтетический пример:

   if ((depost = getDeposit()) && (deposit > 100) && (ACTIVE == getCustomerState()))
   {
    ...
   }
в
   inline bool isDepositEnoughToPay() const
   {
     const dword deposit(getDeposit());
     return deposit > getMinimumAllowedDeposit();
   }

   inline bool isActiveCustomer() const
   {
     return ACTIVE == getCustomerState();
   }

   inline bool isGoodCustomer() const
   {
      return isDepositEnoughToPay() && isActiveCustomer();
   }

   if (isGoodCustomer())
   {
     ...
   }
Наглядно? Читается как предложение на английском и никакой кучи условий.

Самый правильный вариант: декомпозиция. Если много условий в if, то стоит задуматься о разделении обязанностей.

anonymous
()
Ответ на: комментарий от anonymous

если бы все было так просто... каша в гуях получается уже после разумного уровня декомпозиции. Никакой логики, только желания заказчика, который требует всё больше и больше фич. Каждая следующая фича требует либо рефакторинга (иногда серьезно), либо костылей.

сказка? вот живой пример: недавно писали сайт, которому уже лет шесть, и его писало невообразимое множество компаний и фрилансеров. На рефакторинг создатели забили, кажется, уже года через два после старта. В каше из тысяч ифов, написанных «как предложение на английском» уже невозможно разобраться никаким образом (иногда через and там написаны взаимоисключающие параграфы, методы, которые в ходе эволюции кода сменили свое предназначение на прямо противоположное). Только дописывать в конец ифа условия - еще и еще. И вот тут-то и помогает конвеншен - один элемент языка на одной строчке.

stevejobs ★★★★☆
()

это помогает сильно упростить код. сравни

	if ((it = args.find("file")) == args.end() || (file = it->second, false)) {
		throw logic_error("'file' argument must be set"); 
	}
и
	it = args.find("file");
	if (it == args.end()) {
		throw logic_error("'file' argument must be set"); 
	} else {
		file = it->second;
	}

Reset ★★★★★
()
Ответ на: комментарий от Reset

У тебя очень своеобразное представление об упрощении.

unsigned ★★★★
()
Ответ на: комментарий от anonymous

Покажи как

Стандартная документация не очень — я смутно представляю, как работать с http://docs.factorcode.org/content/article-macros.html и с http://docs.factorcode.org/content/article-parsing-words.html
Но как я понимаю, есть два пути: использовать parsing words, но тогда запись будет вида
dosomething [aif [ it print ] [ «error» print ] ] (а это уже начинает превращаться в лисп)
Или же отказаться от цитат, и использовать нечто мощнее, например fry.
-> «world!» '[ «hello» print _ print ] call
hello
world!
Тогда аналог aif будет dosomething '[ _ print ] [ «error» print ] if*.
Но скорее всего, можно гораздо гибче, но я не осилил.
---
Кстати, [let «str» :> var [ var print ] ] превращается в [ «str» 1 load-locals 0 get-local 1 drop-locals print ], ибо [let — parsing word.

quantum-troll ★★★★★
()

Однозначно чтобы студент написал if (c = getchar() != EOF), а потом сидел и пытался понять, «почему дома работало, а здесь нет?».

blueface
()
Ответ на: комментарий от drBatty

комментарии в коде с иллюстрациями от разработчика?

BattleCoder ★★★★★
()
Ответ на: комментарий от quantum-troll

Ну с постфиксными макросами должны возникнуть проблемы.

А зачем нужны постфиксные макросы в префиксном Лиспе?

anonymous
()
Ответ на: комментарий от anonymous

Просто

Это, Вы батенька, чего -то не заметили. gensym например. :)

Макросы в CL это расплата за компилятор и отказ от классической идеи лиспа: код = данные.

anonymous
()
Ответ на: комментарий от anonymous

Это, Вы батенька, чего -то не заметили. gensym например. :)

gensym в этом примере не нужен. Никаких проблем с ним нет.

Макросы в CL это расплата за компилятор и отказ от классической идеи лиспа: код = данные.

Чего-чего?

Макросы - это не расплата, это подарок. Ничего подобного в большинстве языков и в помине нет. А там где есть, далеко до простоты и гибкости.

отказ от классической идеи лиспа: код = данные.

Бред какой-то, макросы как раз и работают с кодом как с данными.

anonymous
()
Ответ на: комментарий от anonymous

gensym в этом примере не нужен. Никаких проблем с ним нет.

К сожалению, нужен. Без него можно получить кучу проблем на ровном месте, например, во вложенном aif.

То, что макросов где-то нет, не означает что они очень нужны в лиспе. Простотой здесь и не пахнет. Относительная гибкость достигается за счет усложнения языка. Вы ведь уже заметили, что писать макос нужно не так как функцию. Другой синтакис.

Бред какой-то, макросы как раз и работают с кодом как с данными.

Да, но только до компиляции. Потом увы нет.

anonymous
()
Ответ на: комментарий от anonymous

К сожалению, нужен. Без него можно получить кучу проблем на ровном месте, например, во вложенном aif.

Это же пример, я сначала для Factor поставил условие. Смысл в сравнении.

То, что макросов где-то нет, не означает что они очень нужны в лиспе.

Они там очень нужны для создания eDSL'ей. Иначе и Лисп не нужен.

Простотой здесь и не пахнет.

Проще еще не придумали. Новые абстракции пишутся также легко, как новые функции или структуры данных. Это с учетом того, что в обычных языках надо слезно умолять разработчиков и ждать годами нужную фичу. Куда уж проще.

Относительная гибкость достигается за счет усложнения языка. Вы ведь уже заметили, что писать макос нужно не так как функцию. Другой синтакис.

Backquote-то? Это конструкция языка и к макросам отношения не имеет. В макросах можно использовать все штатные возможности, ничего левого там нет.

Да, но только до компиляции. Потом увы нет.

Так они для этого и нужны. Я пока не врубаюсь, о чем вообще речь.

anonymous
()
Ответ на: комментарий от anonymous

То, что макросов где-то нет, не означает что они очень нужны в лиспе.

Они там очень нужны для создания eDSL'ей.

Там - это в CL? И нужны для создания компиляторов для eDSL? В этом случае наши точки зрения совпали: макросы - костыль который нужен поскольку нам хочется иметь компилятор в лиспе.

Но лисп != CL. И DSL легко сделать в лиспе и без макросов.

В макросах можно использовать все штатные возможности

.. доступные на момент компиляции.

Проще еще не придумали. ... Куда уж проще

О том я и говорю, что придумали и давно. CL создавался, чтобы быть быстрым и мощным, а не простым и удобным.

Иначе и Лисп не нужен

Я бы уточнил: Common Lisp мне сейчас не нужен, хотя активно и с удовольствием использую другие лиспы.

anonymous
()
Ответ на: комментарий от anonymous

Там - это в CL?

Везде, где есть defmacro.

И нужны для создания компиляторов для eDSL?

Да.

В этом случае наши точки зрения совпали:

Не совпали.

DSL легко сделать в лиспе и без макросов.

Ну покажи aif для примера.

.. доступные на момент компиляции.

Да, весь Лисп доступен.

О том я и говорю, что придумали и давно.

Показывай.

anonymous
()
Ответ на: комментарий от anonymous

К сожалению, нужен. Без него можно получить кучу проблем на ровном месте, например, во вложенном aif.

Покажи как это макрос реализуется с gensym.

korvin_ ★★★★★
()
Ответ на: комментарий от anonymous

DSL легко сделать в лиспе и без макросов.

Ну покажи aif для примера.

: (de aif (It . Prg)
     (if It (eval (car Prg)) (mapc eval (cdr Prg))))
-> aif
: (aif (+ 2 2)(prinl It)(prinl "Error"))
4
-> 4
: (aif (< 2 0)(prinl It)(prinl "Error"))
Error
-> "Error"

В этом варианте aif - нормальная функция, которую можно скормить другой функции, установить точку останова или провести трассирование. С макросами такой фокус не пройдет.

О том я и говорю, что придумали и давно.

Показывай.

Лови:

http://www.software-lab.de/doc/faq.html#macros http://www.software-lab.de/down.html

anonymous
()
Ответ на: комментарий от anonymous

Вы ведь уже заметили, что писать макос нужно не так как функцию. Другой синтакис.

defun и defmacro это макросы, они могут много чего делать, но суть первого сводится к:

(setf (symbol-function 'foo) #'(lambda (x) x)) ;; (defun foo (x) x)

;; (foo 1) => 1

а второго:

(setf (macro-function 'foo) #'(lambda (whole env) (destructuring-bind (form x) whole `(,x)))) ;; (defmacro foo (x) `(,x))

;; (macroexpand-1 '(foo 1)) => (1) T

defun и defmacro, по сути, просто удобнее использовать.

И то и другое - просто функции, каждая в своей таблице, которые использует метациклический вычислитель (одни во время expand-а, другие во время eval-а, eval и expand связаны взаимной рекурсией и могут чередоваться сколько угодно раз).

Да, но только до компиляции. Потом увы нет.

За стадией компиляции может следовать стадия выполнения, за которой снова следовать стадия компиляции, за которой... Метацикличность же - можно сколько угодно вызывать eval, compile, macroexpand и т.п. В CL нет строгого «вот стадия компиляции, вот стадия выполнения, и всё», там можно этот цикл сколько угодно раскручивать.

quasimoto ★★★★
()
Ответ на: комментарий от korvin_

Не взлетит, ты не сможешь пользоваться этим it в then и else, т.к. это будет другой символ.

Да, по-поводу gensym я неправ. Приношу свои извенения моему тезке.

anonymous
()
Ответ на: комментарий от quasimoto

Все это правильно, но за все надо платить. За свою мощь и возможность компиляции CL заплатил усложненим языка и размером бинарника. Кроме того скомпилированная программа не может быть так же легко преобразованна в данные, как её исходник. Именно поэтому, я и усомнился в простоте системы макросов и ее необходимости для всех лиспов без исключения.

anonymous
()
Ответ на: комментарий от anonymous

В этом варианте aif - нормальная функция

Это уже интерпретатор получается. Нам компилятор нужен.

anonymous
()
Ответ на: комментарий от anonymous

За свою мощь и возможность компиляции CL заплатил усложненим языка и размером бинарника.

Усложнение языка это, в основном, совместимость Обще Лиспа с теми лиспами которые он обобщал (многочисленные стандартные типы, функции и макросы). А так, в основе лежит идея об обновляемом образе, циклически связанные стадии (load, compile, execute), набор примитивных типов и 25 специальных форм. Всё остальное надстраивается. Размер бинарника - вопрос технический, есть интерпретаторы CL; компиляторы, в принципе, могли бы генерировать урезанные версии программ (как LispWorks) или хранить вычислитель, компилятор и стандартные функции в разделяемой библиотеке с которой линковать основной (небольшой) бинарник, или распространять программы в (лёгком) байткоде, который JIT-ировать во время load (как jar-ы).

Кроме того скомпилированная программа не может быть так же легко преобразованна в данные, как её исходник.

Тогда бы это был язык со встроенной поддержкой реверс инжининга :) (проприетарщина, например, не хочет по умолчанию показывать свои данные и код). В принципе, можно сделать так, чтобы s-exp-ы определений хранились в образе вместе со скомпилированным кодом (написать свои def* для этой цели и завести соответствующие хэш-таблицы, кстати, в Clojure есть metadata - там это проще делать).

Именно поэтому, я и усомнился в простоте системы макросов и ее необходимости для всех лиспов без исключения.

Ну макросы либо есть, либо их нет. В CL макросы это тоже «нормальные функции», только их expand-ер использует, чтобы сделать макросы на основе «обычных» функций (которые использует сам вычислитель) нужно изменить их стратегию вычисления с энергичной на какую-то другую (call by macro expansion), что не есть хорошо. Вот в PicoLisp какая стратегия вычислений функций? Макросом можно определить, например, логический or стратегия вычисления которого не строгая:

CL-USER> (or t (print 0))
T
CL-USER> (or nil (print 0))

0 
0

В NewLisp, помнится, сделали какое-то непотребство со стратегией вычисления, там тоже «простоту» ценят.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Макросом можно определить, например, логический or стратегия вычисления которого не строгая:

Здесь это уже в языке из коробки:

: (or NIL (prinl "0"))
0
-> "0"
: (or T (prinl "0"))
-> T

но конечно, при желании, все можно поменять на свой вкуc. И, увы, совместимость с древними лиспами была принесена в жертву удобству и здравому смыслу.

или распространять программы в (лёгком) байткоде

исходный код + байткод + бинарник на каждую платформу! По-моему, к простоте это не имеет отношения.

anonymous
()
Ответ на: комментарий от anonymous

Здесь это уже в языке из коробки

Как здесь:

(de aif (It . Prg)
  (if It (eval (car Prg)) (mapc eval (cdr Prg))))
задается стратегия вычисления? Как интерпретатор определяет, что аргументы не нужно вычислять?

korvin_ ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.