Поддерживает ли HaskellDB outer join?
Похоже outer join не по зубам monad-ическому подходу.там лишь стандартная ситуация, что тип колонки T необходимо заменять на Nullable(T соответственно, чел решил этим не заморачиваться, и не усложнять код.
там лишь стандартная ситуация,стандартная ситуация для чего? для того, что абстракции текут? да, это хороший пример протечки абстракции.
что тип колонки T необходимо заменять на Nullable(T
да, требование крайне простое, а реализация "difficult (or even impossible)"
соответственно, чел решил этим не заморачиваться, и не усложнять код.
скорее просто не смог, хотя помимает, что outer join-ы нужны "I didn’t want to give up outer joins so easily".
могу подробнее расписать почему не получилось на C#-е
да, требование крайне простое, а реализация "difficult (or even impossible)"почему так считаешь?
> могу подробнее расписать почему не получилось на C#-е
напиши, пожалуйста
Тьфу, стрикт тип чекинг - это кал.
Тьфу, стрикт тип чекинг - это кал.обоснуй, пожалуйста
Это мое мнение основанное на применении языков с разным уровнем контроля типов. Сам контроль, впрочем, может быть полезен, но в Хаскелле он просто параноидальный из-за ленивости.
он просто параноидальный из-за ленивости.на первый взгляд, второе не связано с первым. какие ты между ними видишь причинно-следственные связи?
Связь не прямая. Ленивость порождает больше возни с типами - нельзя присвоить значение переменной, весь ввод-вывод через монады, которые соответственно заражают код. В общем, на Окамле, где сходная типизация, легче писать чисто субъективно. А весь контроль типов мне не нравится потому, что приходится тратить время на решение проблем с самими типами - типа пишешь что-нибудь, что валидно с точки зрения задачи, но система типов этого не понимает.
Ленивость порождает больше возни с типамиименно вот эту связь не вижу.
для ленивости достаточно иммутабельности и инкапсуляции, а типы вообще не нужны
ленивость появилась в haskell-е по другой причине, строгие языки намного проще развивать, и дешевле вносить кардинальные изменения - потому что намного проще обеспечить, чтобы унаследованный код работал и на новом языке.
для ленивости достаточно иммутабельности и инкапсуляцииЛенивость (call by need с мемоизацией) требует для этой мемоизации ссылочную прозрачность, та - чистоту, а гарантия чистоты уже требует ужимок и прыжков вроде уникальных типов или монад, т.е. "возню с типами".
для этой мемоизации ссылочную прозрачностьссылочной прозрачностью что называешь?
та - чистотуэто не требуется
ОО-патерн - создание по первому требованию - является одним из вариантов реализации "ленивости". и для его реализации не требуется никакая чистота.
а гарантия чистоты уже требует ужимок и прыжков вроде уникальных типов или монад, т.е. "возню с типами".масло масленное.
гарантии имеют смысл только для статически-типизированных языков, для языков без типов уровня компиляции - ни о каких гарантиях речь не идет.
при этом в языке - нет ref. transparency, чистоты и монад, а yield при этом широко используется.
An expression is said to be referentially transparent if it can be replaced with its value without changing the behavior of a program (in other words, yielding a program that has the same effects and output on the same input). The opposite term is referentially opaque.
http://en.wikipedia.org/wiki/Referential_transparency_%28com...
это не требуется
ОО-патерн - создание по первому требованию - является одним из вариантов реализации "ленивости". и для его реализации не требуется никакая чистота.
Требуется. Еще раз: ленивость - это call by need + memoization (sharing).
Из вики: In programming language theory, lazy evaluation or call-by-need is an evaluation strategy which delays the evaluation of an expression until the value of this is actually required (non-strict evaluation) and which also avoids repeated evaluations (sharing).
Твой паттерн - это еще не настоящая ленивость. Нужно еще, чтобы последующие обращения не начинали вычисление заново, и вот тут нужна ссылочная прозрачность.
гарантии имеют смысл только для статически-типизированных языков, для языков без типов уровня компиляции - ни о каких гарантиях речь не идет.
Без гарантий ни о какой ленивости тоже речи не идет.
в моем понимании, yield в C# - это поддержка языком ленивости для одного частного случая: последовательности.yield в C# - это "жалкое подобие левой руки", а не ленивость. И даже там монада есть: SelectMany - ее bind.
при этом в языке - нет ref. transparency, чистоты и монад, а yield при этом широко используется.
http://blogs.msdn.com/b/wesdyer/archive/2008/01/11/the-marve...
Твой паттерн - это еще не настоящая ленивость.в паттерн "создании по первому требованию" - мемоизация входит.
> Твой паттерн - это еще не настоящая ленивость.
вот это настоящая ленивость или нет? и это реализуется почти на любом языке
var x = Lazy=>ДолгаяФункция;
switch
{
case 1:
return 1;
case 2:
return x;
case 3:
return x * x;
}
Func<T> Lazy<T>(Func<T> f)
{
T cache = default(T);
var isCalled = false;
return =>
{
if (!isCalled)
{
cache = f;
isCalled = true;
}
return cache;
};
}
И даже там монада есть: SelectMany - ее bind.SelectMany никакого отношения к Bind-у не имеет.
в приведенном тобой статье Bind реализуется в виде функции с именем SelectMany для того, чтобы можно было использовать синтаксический сахар C# (который реализован для функций с именем SelectMany) для вызова Bind
SelectMany никакого отношения к Bind-у не имеетEric Meijer и компания
(и тут я ссылаюсь не на авторитет, а на экспертизу)
Вот монадный bind из хаскеля:
(>>=) :: forall a b. m a -> (a -> m b) -> m b
А вот SelectMany из IEnumerable в .NET:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector
)
Близнецы-братья. А говоришь, никакого отношения.
Это очень похоже на то, как ленивую конструкцию делают в строгих языках. Пара моментов:
return x * x;
будет вести себя корректно только если x - чистая функция. Иначе жди трудноуловимых сюрпризов.
Теперь представь, что у нас весь язык ленивый, т.е. ленивость - не отдельная странная редкоиспользуемая конструкция, а основная стратегия вычислений. Как там будут вести себя нечистые функции, как будет работать ввод-вывод? Чтобы это хоть как-то взлетело, нужно придумывать способы упорядочивания эффектов, опять привет монады или другие трюки с типами. Есть ли грязные ленивые или динамически типизированные ленивые языки? Я не видел. Может, ты знаешь такие?
ленивость появилась в haskell-е по другой причине, строгие языки намного проще развивать, и дешевле вносить кардинальные изменения - потому что намного проще обеспечить, чтобы унаследованный код работал и на новом языке.Все неверно. Хаскель изначально создан ленивым, ленивость там не появлялась. Хаскель весьма хреново развивается, как и остальные ленивые языки.
в моем понимании, yield в C# - это поддержка языком ленивости для одного частного случая: последовательности.Ленивый язык и оператор, имитирующий ленивость - это радикально разные вещи.
при этом в языке - нет ref. transparency, чистоты и монад, а yield при этом широко используется.
Ленивый язык и оператор, имитирующий ленивость - это радикально разные вещи.разве в haskell-е каждая инструкция ленивая?
в хаскеле операции являются ленивыми, только если они не входят в трассу non-strict редукции
будет вести себя корректно только если x - чистая функция. Иначе жди трудноуловимых сюрпризов.чистота не является необходимым условием для корректности.
верно даже более сильное утверждение: корректная функция не обязана быть детерминированной.
а чистота требует именно детерминированности.
вот этот код корректный, хоть под ленивостью и мемоизацией не чистая функция (соответственно, утверждение - "будет вести себя корректно только если x - чистая функция" - неверно)
var x = Lazy=>rnd;
switch
{
case 1:
return 1;
case 2:
return x;
case 3:
return x * x;
}
Func<T> Lazy<T>(Func<T> f)
{
T cache = default(T);
var isCalled = false;
return =>
{
if (!isCalled)
{
cache = f;
isCalled = true;
}
return cache;
};
}
ленивое исполнение - это на вопрос "сколько будет 2 *2?" дается ответ: "мне лениво считать, поэтому вот тебе замыкание =>2*2, его и спроси".
ленивая декларация - если код входит в несколько трасс выполнения, и исполняется не в каждой трассе, то он помечается оператором ленивости.
х * х
должен вывести две строки, однако в твоем подходе выведет одну. Чистой должна быть функция, чистой.
Про хаскель ты уж совсем что-то напридумывал. Пошел бы лучше прочитал о нем что-нибудь.
Вот монадный bind из хаскеля:здесь необходимо определиться, как сравниваются bind и SelectMany? по сигнатуре, по семантике, по реализации?
например, для SelectMany зафиксирована частное требование, что значение типа IEnumerable<IEnumetable<T>> функция SelectMany переводит в значение IEnumerable<T>, при этом если какой-это элемент был в исходной последовательности последовательностей, то он должен присутствовать и в результате.
для bind-а насколько я понимаю, такая семантика не требуется.
я готов согласиться, что подмножество bind изоморфно подмножеству SelectMany, но вообще это два разных морфизма.
Если в х есть эффект, например вывод строки на консоль, то при корректной работеформулируй правильно.
х * х
должен вывести две строки, однако в твоем подходе выведет одну. Чистой должна быть функция, чистой.
функция обязана не влиять на интересующую часть результата (в твоем примере не влиять на консоль но не обязана не влиять на весь результат(быть полностью чистой например, в функции может присутствовать random, или функция может влиять на stderr, если нам пофигу что там пишется
или более формально: результат можно представить как композицию двух частей: неизменную(непосредственно интересующий нас результат) и вариабельную(шум например, при выводе множества (не задан порядок элементов) (a, c, b) на консоль правильными выводами будет:
a, b, c,
a, c, b,
b, a, c,
b, c, a,
c, a, b,
c, b, a
остальные варианта вывода не правильные.
для данного результата: неизменной частью является, что в выводе присутствует все элементы не более одного раза, вариабельной частью результата(шумом) является порядок вывода.
и соответственно, функция вывода множества обязана быть чистой с точки зрения "наличия элементов", но не обязана быть чистой с точки зрения порядка вывода элементов(с точки зрения шума).
Тут ты частный случай пытаешься подкрутить. Давай посмотрим глобальнее: ленивый язык. В нем все операции по умолчанию ленивые. Какие эффекты разрешить, какие запретить? Как описывать и использовать грязные функции? Я уже спрашивал выше, ответа пока не последовало.
здесь необходимо определиться, как сравниваются bind и SelectMany? по сигнатуре, по семантике, по реализации?По сигнатуре и семантике. Реализация у bind может быть очень разная - для каждой монады своя. Собственно, и для SelectMany там приводят разные реализации. Но есть законы монады, входящие в ее определение, они диктуют ряд равенств, которые должны выполнятся. В статье по ссылке показано, как интерфейс IEnumerable отвечает сигнатуре монады, а дефолтная реализация ее законам, т.е. по меньшей мере является ее частным случаем (List monad). Но и некоторые другие монады можно этим интерфейсом выразить, там есть примеры.
например, для SelectMany зафиксирована частное требование, что значение типа IEnumerable<IEnumetable<T>> функция SelectMany переводит в значение IEnumerable<T>, при этом если какой-это элемент был в исходной последовательности последовательностей, то он должен присутствовать и в результате.Насколько я понимаю, это требование в монаде List выполняется автоматически как следствие из монадных законов.
для bind-а насколько я понимаю, такая семантика не требуется.
в моем понимании, yield в C# - это поддержка языком ленивости для одного частного случая: последовательностине с той стороны смотришь
рекомендую освоить
http://en.wikipedia.org/wiki/Continuation
http://en.wikipedia.org/wiki/Call-with-current-continuation
что такое call/cc я до сих пор не понимаю
зато запомнил, что yield реализуется с помощью двух call/cc, но все равно не понимаю этого
мозгодробительная вещь !
пересказываешь хаскеллистов, однако не пытаешься взглянуть на все это с другой колокольни
вот как можно взглянуть:
Если в х есть эффект, например вывод строки на консоль, то прикорректнойстрогой работе
х * х
должен вывести две строки, однако втвоемленивом подходе выведет одну
что такое call/cc я до сих пор не понимаюв первом приближении, это как исполнение кода выглядит с точки зрения интерпретатора.
call/cc - это один шаг интерпретатора
Если в х есть эффект, например вывод строки на консоль, то при корректной строгой работеНе, я исхожу из написанного тобой кода. Который на строгом языке, но с имитацией ленивого вызова обозначенной функции. Там x*x выполняется в строгом контексте.
х * х
должен вывести две строки, однако в твоем ленивом подходе выведет одну
В ленивом языке операция умножения чисел вычисляет оба аргумента, так что однократный вывод все равно никак не должен получаться.
Давай посмотрим глобальнее: ленивый язык. В нем все операции по умолчанию ленивые.язык в котором все операции по умолчанию ленивые - это который выводит:
Prelude> 2 * 2 + 2
2 * 2 + 2
и в котором для того, чтобы что-то вычислить необходимо это явно записать (где $ - это оператор форсированного выполнения (strict-выполнения
Prelude> $(2 * 2 + 2)
6
и даже strict-оператор может быть ленивым, когда он за раз выполняет только одну инструкцию (раскрывается только один call/cc):
Prelude> $(2*2+2)
4+2
Prelude> $$(2*2+2)
6
кстати, на самом же haskell.org пишут, что haskell не является ленивым языком, он является non-strict языком
Haskell is often described as a lazy language. However, the language specification simply states that Haskell is non-strict, which is not quite the same thing as lazy.http://www.haskell.org/haskellwiki/Lazy_vs._non-strict
1 Direction of evaluation
Non-strictness means that reduction (the mathematical term for evaluation) proceeds from the outside in,
[...]
если код входит в несколько трасс выполнения, и исполняется не в каждой трассе, то он помечается оператором ленивости.
Давай посмотрим глобальнее: ленивый язык. В нем все операции по умолчанию ленивые. Какие эффекты разрешить, какие запретить? Как описывать и использовать грязные функции? Я уже спрашивал выше, ответа пока не последовало.на этот вопрос сложно ответить, потому что вопрос содержит большое кол-во неопределенностей(неточностей).
первая неопределенность: какие виды ленивых языков рассматриваются? надеюсь, тебе уже понятно, что видов ленивости бывает много, и что haskell не является полностью ленивым языком.
вторая неопределенность: кто следит за тем, чтобы код был согласованным? программист или язык?
третья неопределенность: язык разрешает исполнять несогласованной код или нет?
четвертая неопределенность: на основании каких факторов определяется грязность функции?
Про хаскель ты уж совсем что-то напридумывал. Пошел бы лучше прочитал о нем что-нибудь.зачем мне про хаскель что-то читать конкретное, если я знаю как устроено всё множество таких языков.
я могу путать как какая-то запятая устроена именно в хаскеле по сравнению с другими языками, но на общие выводы обычно это не влияет.
не перечислишь три-четыре экземпляра?
разве в haskell-е каждая инструкция ленивая?Да, Нет, Нет.
насколько я помню, ленивое выполнение в хаскелл необходимо явно пометить, что и является ленивым оператором.
в хаскеле операции являются ленивыми, только если они не входят в трассу non-strict редукции
Да, Нет, Нет.это не фальсифицируемо
язык в котором все операции по умолчанию ленивые - это который выводит:
Prelude> 2 * 2 + 2
2 * 2 + 2
Правда? Это где такой? Дай посмотреть. Опять на ходу придумываешь определения?
и даже strict-оператор может быть ленивым, когда он за раз выполняет только одну инструкцию (раскрывается только один call/cc):
Prelude> $(2*2+2)
4+2
Ну уж совсем не надо погружаться в фантазии. Дай определение оператора $ (как он определен в реальном языке а не своей фантазии, увидишь разницу. Ну и про call/cc не надо, пожалуйста, это больно слышать.
кстати, на самом же haskell.org пишут, что haskell не является ленивым языком, он является non-strict языком
А причем тут он вообще? Я говорил о ленивом языке и приводил определение ленивости, не сводя к одному конкретному.
он помечается оператором ленивости.
Покажи, пожалуйста, оператор ленивости в хаскеле, раз уж ты в этом контексте о нем заговорил.
первая неопределенность: какие виды ленивых языков рассматриваются? надеюсь, тебе уже понятно, что видов ленивости бывает много, и что haskell не является полностью ленивым языком.
вторая неопределенность: кто следит за тем, чтобы код был согласованным? программист или язык?
третья неопределенность: язык разрешает исполнять несогласованной код или нет?
четвертая неопределенность: на основании каких факторов определяется грязность функции?
1. определение я дал выше.
2-4. на твое усмотрение.
Как бы ты делал ленивый язык, чтобы на нем можно было писать человеку в своем уме, и оставаться при этом в своем уме? Здесь разрешаю проявить фантазию.
читай до просветления
http://en.wikipedia.org/wiki/Evaluation_strategy
вот спасибо за отличный совет, блеать!
сам бы почитал сперва
я могу путать как какая-то запятая устроена именно в хаскеле по сравнению с другими языками, но на общие выводы обычно это не влияет.Дарк Грей хватить пороть чушь. Хаскель - это ленивый язык, все операторы в нем ленивые. Более того реализован он не посредством каких-то хаков с продолжениями, а специальной редукционной машиной, которая раздирает код на части, которые выполняются в последовательности непостижимой в прямом смысле человеческим мозгом. Т.е. неизвестно какая подчасть программы выполняется когда, неизвестно когда она выполняется относительно "любой" другой, как она мутирует при выполнении и т.п. Нон-стрикт vs lazy не имеет отношения к вопросу, чисто ленивый язык чрезвычайно неэффективен, поэтому в хаскеле допускается иногда явно форсить выражения и только.
call/cc - это один шаг интерпретатораесть тема покопать поглубже, либо поступать, как я и честно заявлять "я этого не понимаю"
язык в котором все операции по умолчанию ленивые - это который выводит:На самом деле Хаскель именно такой. Просто Прелюд форсит выполнение по умолчанию, поскольку выводит значение на консоль. $ тоже существует в хаскеле, там можно зафорсить вычисление немного. Но основной форситель - это ввод-вывод, который немного захардкожен, но довольно элегантно.
Prelude> 2 * 2 + 2
2 * 2 + 2
Правда? Это где такой? Дай посмотреть. Опять на ходу придумываешь определения?
и даже strict-оператор может быть ленивым, когда он за раз выполняет только одну инструкцию (раскрывается только один call/cc):
Prelude> $(2*2+2)
4+2
Ну уж совсем не надо погружаться в фантазии. Дай определение оператора $ (как он определен в реальном языке а не своей фантазии, увидишь разницу. Ну и про call/cc не надо, пожалуйста, это больно слышать.
есть тема покопать поглубже, либо поступать, как я и честно заявлять "я этого не понимаю"Call/cc - это лонг джамп из С по сути. Если думать в таких терминах (т.е. через сохранение стека то понять его работу уже проще.
Если думать в таких терминах (т.е. через сохранение стека то понять его работу уже проще.ага, как-то так меня учили
просто когда мы цепляли консьюмера к продюсеру через эту штуку, то у меня уже голова лопалась
есть тема покопать поглубже, либо поступать, как я и честно заявлять "я этого не понимаю"call/cc - это и есть один шаг интерпретатора.
я упомянул "в первом приближении", потому что дальше надо аккуратно формализовать, что такое интерпретатор, что такое один шаг, что один шаг берет на вход и выдает на выход и т .д.
надо аккуратно формализовать, что такое интерпретаторбеседа с тобой получается непродуктивной, потому что ты изъясняешься на непонятном языке
не надо ничего формализовывать, надо прочитать статью на вики, понять ее и научиться оперировать теми терминами, которые фигурируют в статье
тогда беседа получится конструктивной и другие люди смогут чему-то научиться у тебя
не надо ничего формализовывать, надо прочитать статью на вики и понять ее и научиться оперировать теми терминами, которые фигурируют в статьеэто невозможно.
только функциональных языков можно построить бесконечное множество.
вики же задает названия максимум для десятка терминов(если поковыряться, то может быть сотни)
соответственно, невозможно через десять названий описать бесконечное множество.
Я не знаю какие там "официальные" определения, но для себя считаю так: не надо воспринимать ленивость как "внутреннее" свойство интерпретатора, это понятие, описывающее интерпретатор "снаружи". Ленивый интерпретатор за конечное время средуцирует то, что в принципе за конечное время можно средуцировать. А что там у него внутри, это его дело, если хочется пусть спекулятивно что-то вычисляет. Лишь бы не зарывался и не завис там где можно не зависнуть.
Правда? Это где такой? Дай посмотреть. Опять на ходу придумываешь определения?такие языки описываются с помощью следующей семантики:
тип number - число
тип void - фиктивный параметр для функции с 0-параметров
view const = number | void
тип set - множество (порядок не важен)
тип sq - последовательность (порядок важен)
тип function - функция
alias f = function
тип F = const | function(sq(F
тип ast=F - дерево, где в нелистовых узлах размещены функции
tree-reduce(ast, правила-редуцирования) - избавиться от символа $ на основе правил-редуцирования:
на каждом шаге дерево обходится в глубину,
применяется однократно первое подошедшее правило,
после применения правила происходит выход из шага,
если не одно правило не было применено происходит выход из функции
фактически это модификация Нормального алгоритма Маркова для дерева
prelude(код) = преобразовать-в-ast(код).начальная-модификация-ast.редуцировать-ast.ast-преобразовать-в-человеческую-строку
редуцировать-ast(ast) = tree-reduce(ast, правила-редуцирования)
Language-1:
начальная-модификация-ast(ast)=ast;
правила-редуцирования:
$const -> const
$f(const, const) -> execute(f(const, const
$f(a1,a2) -> $f($a1, $a2)
Language-2:
начальная-модификация-ast(ast)=ast;
правила-редуцирования:
$const -> const
$f(const, const) -> execute(f(const, const
$f(const, a2) -> f(const, $a2)
$f(a1, a2) -> f($a1, a2)
Language-3 inherit Language-1:
override начальная-модификация-ast(ast)=$ast;
Language-1 задает поведение
Prelude> 2 * 2 + 2
2 * 2 + 2
Prelude> $(2 * 2 + 2)
6
Prelude> $$(2 * 2 + 2)
6
Language-2 задает поведение
Prelude> 2 * 2 + 2
2 * 2 + 2
Prelude> $(2*2+2)
4+2
Prelude> $$(2*2+2)
6
Language-3 задает поведение
Prelude> 2 * 2 + 2
6
Prelude> $(2 * 2 + 2)
6
Prelude> $$(2 * 2 + 2)
6
зы
в данном случае не рассматривается вариант, когда для некоторых функций можно рассчитывать не все параметры.
для большего ожидайте cледующей версии
ззы
для функций с произвольным кол-вом параметров правила редуцирования(и их кол-во) все теже, необходимо только усложнить правила описания правил редуцирования.
На самом деле Хаскель именно такой. Просто Прелюд форсит выполнение по умолчанию, поскольку выводит значение на консоль.Prelude - это просто библиотека, ничего она не форсит.
Когда мы подаем некоторое выражение Е в ghci, он строит санк для Е, по его типу выбирает инстанс класса Show, и если тот есть, скармливает санк в функцию show из этого класса. Эта функция строгая по своему параметру. Оказавшись в строгом контексте, выражение вычисляется (приводится в head normal form).
$ тоже существует в хаскеле, там можно зафорсить вычисление немного.Во-первых, $ - это просто аппликация, f $ x = f x, ничего он не форсит. Форсит другой оператор, похожий ($!).
Но основной форситель - это ввод-вывод, который немного захардкожен, но довольно элегантно.Это лишь частный случай. Главный форситель - рантайм, стремящийся редуцировать main. Если там для этого требуется ввод-вывод, он будет произведен, нет - нет. Вся программа как одно выражение оказывается в строгом контексте, начинаются редукции. Многие редексы, чтобы быть редуцированы, требуют приведения их параметров в надлежащую форму, так их параметры оказываются в строгом контексте и тоже вычисляются. Например, + форсит оба параметра для своего вычисления. Паттерн-матчинг тоже форсит. show форсит. И т.д.
> Правда? Это где такой? Дай посмотреть. Опять на ходу придумываешь определения?И где на них можно посмотреть? Есть реальные примеры? Мир твоих фантазий для нас закрыт, извини.
такие языки описываются с помощью следующей семантики: ...
И где на них можно посмотреть? Есть реальные примеры? Мир твоих фантазий для нас закрыт, извини.по этой семантике ты не можешь построить язык? там же всё разжевано. тем более ты вроде как haskell знаешь - там это вообще должно делаться в одну строчку...
Ок, т.е. такого языка еще нет. У тебя очень здорово получается рассказывать о том, чего нет. Спасибо.
вот спасибо за отличный совет, блеать!Ему лениво.
сам бы почитал сперва
Ок, т.е. такого языка еще нет.изначально шел разговор о терминах (в частности, что такое язык, в котором все операторы по умолчанию ленивые)
сейчас же ты говоришь, что раз языка нет, то и не нужны термины для его описания. я правильно излагаю твою позицию?
в каких тогда терминах говорить об изменении языков, или о создаваемых языках?
зы
кстати, статью на haskell.org, я полагаю, ты не осилил, в которой они пишут, что lazy != non-strict.
я правильно излагаю твою позицию?
Нет.
Ты ударился в термины, чтобы уйти от основной темы, стандартный демагогический прием.
Разница между non-strict и lazy несущественна в данной теме. Например, в отношении хаскеля она настолько несущественная, что если пойти на haskell.org и кликнуть "What is Haskell?", можно прочитать:
Haskell is a computer programming language. In particular, it is a polymorphically statically typed, lazy, purely functional language, quite different from most other programming languages.
Еще в стахтысячахпятисот местах хаскель неглупые люди (включая его авторов) называют ленивым языком, поэтому уход в дебри фантазий о "настоящих" ленивых языках тут не особо нужен.
зы
кстати, статью на haskell.org, я полагаю, ты не осилил, в которой они пишут, что lazy != non-strict.
Если это тебя так волнует, спешу сообщить, что я ее осилил и во-первых счел несущественной (тем более, что там говорится `in most cases the terms "lazy" and "non-strict" are synonyms.` а во-вторых нашел в ней ряд
А чем тебя эта ссылка так возбудила?если есть разница, в данном случае - это разница между lazy и non-strict, то дальше можно поставить следующие вопросы:
можно ли построить язык, который будет занимать промежуточное положение между lazy и non-strict?
можно ли построить язык, который будет более lazy, чем текущий lazy-вариант?
можно ли построить язык, который будет менее lazy, чем текущий non-strict вариант?
если можно построить, то что при этом улучшиться, а что ухудшится?
зы
более ленивый язык построить можно(чем haskell это Language 1 (Haskell - это соответственно, Language 3):
в минус - его менее удобно использовать, как универсальный язык,
в плюс - проще описание семантики, легче использовать при композиции (в частности как субмодуль другого языка или программы)
Например, в отношении хаскеля она настолько несущественная, что если пойти на haskell.org и кликнуть "What is Haskell?", можно прочитать:неверный логический переход (из верности частного утверждения делается вывод о верности всего общего утверждения)
она несущественна для автора цитаты в том контексте, в котором он ее говорил, но это не означает, что это несущественная разница для всего haskell-я и всех его применений.
Haskell - это соответственно, Language 3
Не верю, у тебя там же фигня написана. Что такое $f($a1, $a2)? В каком порядке выполняются редукции тут? Зачем выполняются $a1 и $a2? В хаскеле функция f может не использовать аргументов, тогда переданные в качестве аргументов выражения вообще не будут вычислены. А у тебя они вычисляются.
Что такое $f($a1, $a2)? В каком порядке выполняются редукции тут? Зачем выполняются $a1 и $a2?это не выполнение - это замена одних символов на другие.
раньше S-expr было $(*(1,+(3, 1 а после отработки правила: ($(*($(1$(+(3,1
Оно происходит только при вычисленных до констант аргументах? Тогда это точно не хаскель.
Это не правда. Например бесконечный список бесконечно печатается. Если бы было как ты говоришь, он бы бесконечно вычислялся, и ничего бы не печаталось.
Я потому и сказал про head normal form, там у списка хвост остается не вычисленным, все нормально. Мне стоило пояснить, что "строгая по параметру" означает, что переданный параметр приводится в head normal form, т.е. вычисляется не целиком, а до первого конструктора, грубо говоря.
[xoft ~]$ cat x.hs
data X = X
instance Show X where
show _ = "X"
x = undefined :: X
[xoft ~]$ ghci x.hs
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( x.hs, interpreted )
Ok, modules loaded: Main.
*Main> x
X
В общем смысл в том, что функция show ничем не особенная, такая же ленивая как все остальные. Форсируется её значение, а не аргумент.
Я же сказал, что по типу выбирается инстанс класса, у разных типов разные show. Действительно, можно для своего типа задать такую вот show, не использующую аргумент. Но для интов, про которые были примеры выше, (и многих других базовых типов) она уже есть, и аргумент форсит. Т.е. да, я неправильно обобщил это на все show. Сама show не является чем-то особенным, просто многие ее реализации строгие по параметру, и тот, что использовался в примерах выше, такой.
Давай внесем конструктива и вот о чем поговорим. Возьмем описанные выше Language 1-3, выбери один из них на твой вкус или опиши несколько отличный Language 4, и добавь конструкции для ввода-вывода чисел и для изменяемых (не персистентных) массивов. Но основная семантика должна оставаться ленивой или нестрогой (на твой выбор, если считаешь эту разницу важной). Потом попробуем написать на них пару простых программ и посмотрим, какие дополнительные условия и конструкции нам могут понадобиться.
почему так считаешь?Представь запрос, который состоит из некоторого количества LEFT OUTER, RIGHT OUTER и INNER JOIN. Столбцы в запросе встречаются в выражениях ON и SELECT. Один и тот же столбец в одних ON-ах еще T, а в других уже Nullable<T>. Как такое реализовать на C#? Property же не может иметь разный тип в зависимости от контекста использования. Что можно сделать? Ввести вторую переменную для той же сущности? Но это уже будет синтаксический оверхед по сравнению с SQL-ем.
> могу подробнее расписать почему не получилось на C#-е
напиши, пожалуйста
Я тут посмотрел проект ARel для Ruby on Rails. Без статической типизации составлять AST для SQL-я, конечно, проще. Тут возникает мысль использовать не статически типизированный построитель запросов внутри областей кода, которые валидируются Controllable Query:
MaterializeReader(
_ => {
//здесь используем динамически типизированный построитель
},
context => new {
//здесь определяем какие параметры передаем в динамически типизированную область
})
Это стоит попробовать.
Но мне кажется, что если внимательно сравнить с ARel то существенных преимуществ у ARel нет. Автор ARel отмечает как мегафичу замкнутость относительно операций реляционной алгебры, но он, похоже, не понимает, что и SQL обладает этим свойством.
Оставить комментарий
6yrop
Поверхностное гугление отвечает, что нет, не поддерживает. Но там сообщения от 2008 года. Может что поменялось?В свое время я на C#-е столкнулся с принципиальными сложностями в реализации outer join (произвольной вложенности). Вот тут пишут, что и в Scale на то же самое наткнулись:
Похоже outer join не по зубам monad-ическому подходу.