Здравствуйте, palm mute, Вы писали:
PM>Здравствуйте, BulatZiganshin, Вы писали:
BZ>>что же касается концепции монад, это это уже было обобщение этого паттерна, использование его в других областях. на данный момент можно сказать, что монады — это стратегия вычислений, определяемая отдельно от самих этих вычислений
PM>Со всем согласен, кроме последнего утверждения. AFAIK, применять монады для формализации вычислений впервые предложил Moggi в статье: PM>http://citeseer.ist.psu.edu/moggi89computational.html PM>И уже там говорится, что с помощью монад можно моделировать изменяемое состояние (а не ввод-вывод) и continuations.
PM>Эта статья менее популярна, чем Imperative functional programming (последняя на работу Moggi ссылается), т.к. читателя в ней не жалеют, грузят theoretical computer science по полной программе.
я сейчас подумал и решил, что ошибся уникальные типы — это конкретная реализация IO монады, можно делать и по-другому (в hbc, где они кажется впервые и были реализованы, использовались continuations). так что монады — это вообще не способ *реализации* императивности. это способ описания её в рамках *чистого* языка. а реализовать затем эту >>= иожно и так, и эдак, и анверно ещё другие варианты можно придумать. так что монада — это спецификация поведения >>=, это контракт, а трюк с RealWorld — это реализация, удовлетворяющая этой спецификации
Здравствуйте, EvilChild, Вы писали:
VD>>Авторам этого языка к сожалению не удалось создать язык отвечающий этим требованиям. EC>Что именно из этого списка не удалось? Можешь аргументировать?
1. It should be suitable for teaching, research, and applications, including building large systems.
EC>>>Haskell и есть та экспериментальная площадка, на которой обкатываются идеи, которые попадают в мейнстрим. VD>>Ты внимательно читал то что я написал прежде чем отвечать? Или у тебя прицип в жизни такой отчечать все что угодно лиш бы оно не имело никакого отношения к словм оппонентов? EC>Давай ты оставишь в покое мои припницы. Почему ты вместо ответа на вопрос постоянно переходишь на личности?
Потому что некоторые личности постоянно передергивают, подменяют темы разговра, несут просто откровенную ахинею и на просьбу объяснить связь этой ахинеии с моими высказваниями задают вопрос вместо такго чтобы дать ответ.
Так же эти личности постоянно обрезают задаваемые им вопросы, не отвечая на них.
Так вот в этом случае меня лично просто раздражает странность и не связанность твои ответов. Нопомню еще раз сто я сказал: VD>>Я считаю, что пришло время перевести мэйнстрим на языки которые будут мало отличаться от сегодняшних фоваритов (С++, C# и Java) по эффективности, но при этом дадут возможность существенно поднять уровень разработки.
На что ты мне ответил: EC>Haskell и есть та экспериментальная площадка, на которой обкатываются идеи, которые попадают в мейнстрим.
Извини, но "Кащщено". Кто тебя спрашивал о "площадках"? Речь идет не о эксперементах, а о реальном применении. Причем тут "экспериментальная площадка"? В чем логика?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>собственно, LINQ, как и HaskellDB — интерфейс к БД. в HaskellDB для этого использована специальная монада, которая позволяет пошагово уточнить выполняемый запрос,
Здорово! То есть в Хаскеле для реализации функции Х используется монада. Ну, и причем тут C#? Почему в нем то должно использоваться то что в нем нет, и на фиг не упало?
В Хаскеле и для доступа к файлмам используется монада. И что?
Хотя конечно это вопрос не к тебе, а к тем странным личностям, что пытаются узреть монады в Шарпе.
BZ>и >>= будет стратегией вычислений, формирующей из отдельных вызовов выполняемый оператор sql. в linq, вероятно, точно так же
В linq используются ФВП. Там завели стандартные функции но с другими именами:
Select -> map
OrderBy -> Sort
Where -> Folter
и т.п. Далее сделали для этого дела спец-синтаксис, чтобы можно был писать похоже на SQL-запрос, т.е вместо:
xs.Where(x => x > 3).OrderBy(x).Select(x => new { x.a, x, b })
можно было писать:
from xs where x > 3 order by x select new { x.a, x, b }
и все. А некторые пытаются узреть в этом монады.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, lomeo, Вы писали:
VD>>Слова "query monad, как в HaskellDB, над которым, кстати, он работал" вообще каша какая-то.
L>Если ты чего то не понимаешь, это не значит, что этого нет. Определись, что именно тебе не понятно, спроси знающих людей, уверен, тебе ответят.
Ну, так ты потрудишся объяснить какое отношение монады имеют к C#? И где ты их узрел в LINQ?
Или то основание, что люди подглядели общую идею в Хаскеле где ее реализация была сделана через монады достаточно чтобы считать что в C# появились монады?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, lomeo, Вы писали:
L>Если же под более легкими для понимания сущностями ты имеешь внесение в язык явного императива, то это мы с тобой уже обсуждали: это (минимум) вопросы целей, и цели авторов языка могут не совпадать с твоими.
Именно это я имею в виду. Так будет прямой ответ (да/нет)?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>далее. сделав в языке две ипостаси — чистые функции и процедуры, ты должен будешь продумать язык отдельно для каждой из них, продумать их правила взаимодействия и т.п.
Это не так. Все что нужно (по минимуму) чтобы превратить любй ФЯ в ИЯ = это добавить возможность объявления изменяемой переменной и оператор присвоения. А все императивные конструкции безпробем делаются из функциональных в сочетании с присониями переменных.
BZ>здесь же потери были бы ещё больше. и никакого выигрыша. фактически, сам pure язык позволяет сформулировать концепцию процедуры в нём, используя этот трюк с realworld.
Вот realworld это ханжеский булшит. По сути тот же Хаскель имеет оператор присвоения <- но в извращенно-завуалированной форме. И мы без проблем можем писать инмперативный код, но раком.
BZ> и тогда вместо того, чтобы формулировать правила для процедур отдельно, они просто выводятся из общих правил для любых pure функций, становятся их частным случаем. общее кол-во концепций в языке уменьшается, а это не может не радовать
Если бы такое "уменьшение" было бы благом, то в Хаскеле даже числа были бы перечислениями объявленными в каком-нить модуле. Все же есть вещи которые проще зашить в язык. И императивная составляющая одна из таких вещей.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>>>Авторам этого языка к сожалению не удалось создать язык отвечающий этим требованиям. EC>>Что именно из этого списка не удалось? Можешь аргументировать? VD>
1. It should be suitable for teaching, research, and applications, including building large systems.
В некоторых европейских ВУЗах его используют как первый язык программирования при обучении.
Я правда не настаиваю, что Haskell идеальный язык для этого.
Но с остальными пунктами вроде всё в порядке, согласен?
Просто для несогласия с частью одного пункта из шести, твоё утверждение слишком сильное, не находишь?
Так, что по части передёргивания ты тоже грешен.
VD>Извини, но "Кащщено". Кто тебя спрашивал о "площадках"? Речь идет не о эксперементах, а о реальном применении. Причем тут "экспериментальная площадка"? В чем логика?
В данном конкретном случае соглашусь с тобой — малость невпопад ответил (загнался в полемическом пылу).
В общем давай будем обсуждать не недостатки друг друга (они мало кому кроме нас интересны), а языки программирования.
Здравствуйте, VladD2, Вы писали:
VD>Ну, так ты потрудишся объяснить какое отношение монады имеют к C#? И где ты их узрел в LINQ?
Почему опять трудится должен я? Потрудись перечитать мой ответ. Что тебе в нём непонятно?
VD>Или то основание, что люди подглядели общую идею в Хаскеле где ее реализация была сделана через монады достаточно чтобы считать что в C# появились монады?
Здравствуйте, VladD2, Вы писали:
VD>Именно это я имею в виду. Так будет прямой ответ (да/нет)?
Да (в смысле, прямой ответ — да). Твоё решение, например, более легкое для твоего понимания. Это что нибудь меняет? Легкость в, повторю, первоначальном понимании по твоему является наиважнейшим и единственным фактором при выборе решения?
Здравствуйте, VladD2, Вы писали:
VD>Вот realworld это ханжеский булшит. По сути тот же Хаскель имеет оператор присвоения <- но в извращенно-завуалированной форме. И мы без проблем можем писать инмперативный код, но раком.
Как программист пишет код — хоть на голове, это его личное дело. А вот результат ничем не будет отличаться от императивного кода на другом языке. КАК это представлено внутри — без разницы. Поскольку realworld реально не используется — мы получим обычное последовательное (читай императивное) исполнение кода безо всяких realworld.
Что тебя смущает, не пойму? Выглядит код как императивный, компилируется и работает как императивный, что ещё надо то?
BZ>> и тогда вместо того, чтобы формулировать правила для процедур отдельно, они просто выводятся из общих правил для любых pure функций, становятся их частным случаем. общее кол-во концепций в языке уменьшается, а это не может не радовать
VD>Если бы такое "уменьшение" было бы благом, то в Хаскеле даже числа были бы перечислениями объявленными в каком-нить модуле.
Не придумывай. Дело не в том, что уменьшение не благо, а в том, что это просто невозможно. Во всём остальном числа (целые) ведут себя как обычные перечисления.
VD>Все же есть вещи которые проще зашить в язык. И императивная составляющая одна из таких вещей.
EC>В некоторых европейских ВУЗах его используют как первый язык программирования при обучении. EC>Я правда не настаиваю, что Haskell идеальный язык для этого.
а по-моему, как раз идеальный — чистая математика без всякиз побочных явлений. именно на нём надо изучать понятие алгоритма, учиться составлять их, а затем уже переходить к более никзоуровневым языкам
EC>>В некоторых европейских ВУЗах его используют как первый язык программирования при обучении. EC>>Я правда не настаиваю, что Haskell идеальный язык для этого.
BZ>а по-моему, как раз идеальный — чистая математика без всякиз побочных явлений. именно на нём надо изучать понятие алгоритма, учиться составлять их, а затем уже переходить к более никзоуровневым языкам
Я не настаиваю, но и не отрицаю, правда доказывать не стану — устал буквы писать
Здравствуйте, VladD2, Вы писали:
VD>Но я так и не услышал разумного обяснения того зачем эту сущность не то что вводить в ООЯ, но даже употреблять для объясениях тех или иных концепций?
В общем лови. Часть статьи Вадлера "the essence of functional programming"
Суть какая. Пишется простейший интерпретатор. Типа того что ты приводил в каком-то посте про Nemerle. Потом к нему добавляется обработка ошибок. Потом к нему добавляется вывод позиции ошибки. Причем развитие делается с минимумом телодвижений. По возможности. И с объяснениями как бы это могло выглядеть без монад.
Мой поинт заключается в том, что монадную технику приводимую в статье можно с успехом использовать не только в Хаскеле. То есть код можно практически один в один преписать на Немерле и оно будет работать. Если есть способ написать аналог интерпертатора с меньшими телодвиженями — welcome.
Но еще раз повторюсь моя ИМХа заключается в том, что монадный подход можно использовать и вне Хаскела. Конечно многие веще можно сделать и без него. Но если монады в каком-то одном случае из сотни дадут выигрыш, то почему бы ими не воспольозваться?
Все кусочки готовы к уоптреблению. то есть их можно as is загрузить в интерпретатор Хаскела и поиграться. В последней части меня обломало приводить функции в более понятный вид. Если будет сильно уж непонятно — перепишу. пожелания замечания, этц велкам.
В этом сообщении будет описана база интерпретатора. Остальные части отдельными постами.
Комментарии и описание происходящего — в кмментариях к коду.
-- Имена переменных описываются строкойtype Name = String-- Термом может быть
-- Переменнаяdata Term = Var Name
-- Константа
| Constant Int-- Операция сложения
| Add Term Term
-- Лямбда
| Lambda Name Term
-- Операция вычисления
| Apply Term Term
-- Значением может быть
-- Ошибкаdata Value = Wrong
-- Число
| Num Int-- Функция (Functions are first class values :super:)
| Fun (Value -> M Value)
-- Environment - это переменные окружения, представленные списком пар (Имя, Значение)type Environment = [(Name, Value)]
-- Функция вывода значения
showVal :: Value -> String
showVal Wrong = "<wrong>"-- Для вывода числовых значений используется функция show из стандартной библиотеки Prelude
showVal (Num i) = show i
showVal (Fun f) = "function"-- Ключевая функция - интерпретатор.
interprete :: Term -> Environment -> M Value
-- Интерпретация значения переменной "x" сводится к поиску значения в переменных окружения
interprete (Var x) environment = searchFor x environment
-- Интерпретация константы производится путем возврата монадического значения числа.
-- то есть берем число "i" представляющее константу и запихиваем его в монаду при промощи функции
-- returnM имеющую тип a -> M a
interprete (Constant i) environment = returnM (Num i)
-- Интерпретация операции сложения. Запись более развернутая чем у Вадлера в целях упрощения понимания
-- удобнее рассматривать производящее с конца.
-- возьмем функцию add a b она вернет нам M Value согласно ее типу
-- то есть тип лямбды (\b -> add a b) будет Value -> M Value
-- поднимаемся на строчку выше и рассматриваем строку
-- bindM y_value (Value -> M Value)
-- поскольку bindM имеет тип M a -> (a - M b) -> M b
-- то y_value будет иметь тип M Value , поскольку такой тип у функции interprete, резульаттом работы которой и является y_value
-- а все выражение будет иметь тип bindM M Value (Value -> M Value)
-- то есть просто M Value, а значеним его будет M x+y , то есть сумма чисел x и у, будет внутри монады
-- После упрощения остается bindM x_value (\a -> M x+y)
-- значением лябмды будет M x+y, а ее типом - (Value -> M Value)
-- Следовательно результатом функции interprete (Add x y) е будет значение суммы x+y завернутое в монаду.
interprete (Add x y) environment = bindM x_value
(\a ->
bindM y_value
(\b -> add a b))
where
x_value = (interprete x environment)
y_value = (interprete y environment)
-- Интерпретация применения функции к аргументу. Абсолютно идентична Add x y_value
-- за исключеним того, что возвращаемым значением будет M apply a b
interprete (Apply function argument) environment = bindM function_value
(\a ->
bindM argument_value
(\b -> apply a b))
where
function_value = (interprete function environment)
argument_value = (interprete argument environment)
-- Интерпретация лямбды.
-- Значением выражения будет функция Fun
-- Согласно конструктору типа Fun принимает значение (Value -> M Value)
-- Проверим, так ли это. Расмотрим выражение (\a -> interprete v ((x,a):environment)) 3
-- подставив неопсредственно значение 3 в лямбду получим
-- interprete v ((x,3):environment)
-- таким образом зачением лямбды будет выражение v вычисленное в окружении, в котором х имеет непосредственно значение.
-- иначе говоря сначла мы добавляем в спиоск окружения новую переменную х, а потом вычилсяем значения лямбды
-- как interprete v new_environment, где new_environment = ((x,3):environment)
interprete (Lambda x v) environment = returnM (Fun (\a -> interprete v ((x,a) : environment)))
-- Функция поиска значения переменной в окружении
-- Классический рекурсивный проход по списку. Если значение найдено, возврщается монадическое значение переменной,
-- иначе Wrong
searchFor :: Name -> Environment -> M Value
-- Если добрались до конца спписка или окружение пусто - ошибка
searchFor x [] = returnM Wrong
-- Если имя "х" и имя первой пары в списке окружения "у" равны
searchFor x ((y,b) : environment) = if x ==y
-- то возвращаем значенеthen returnM b
-- иначе продолжим поиск в остальной части спискаelse searchFor x environment
-- Функция сложения
add :: Value -> Value -> M Value
-- если параметрами являются два числовых значения, то возвращаем монадическое значение их суммы
add (Num x) (Num y) = returnM (Num (x+y))
-- иначе возвращаем ошибку
add x y = returnM Wrong
-- Применение функции к аргументу
apply :: Value -> Value -> M Value
-- Если первый агрумент функция, то результатом будет применение функции f к аргументу а
apply (Fun function) argument = function argument
-- Иначе возвращаем ошибку
apply function argument = returnM Wrong
-- Функция test используется для вывода на экран значения терма.
test :: Term -> String-- Интерпретируем терм в пустом окружении, что даст на выходе M Value, и передаем результат в функцию
-- showM, которая имеет тип M Value -> String
test term = showM (interprete term [])
-- тестовый терм для проверки вычиления значения лябмда-выражения
-- (lambda x ( x + x))( 10 + 11) = 42
-- проверка производится в интерпретаторе Haskell путем вызова
--Main> test term0
--"42"
term0 = (Apply (Lambda "x" (Add (Var "x") (Var "x")))
(Add (Constant 10) (Constant 11)))
-- тест который должен возвратить значение типа "функция"
term1 = (Lambda "x" (Add (Var "x") (Var "x")))
-- трививальная монада Identity
-- M a идентично atype M a = a
-- returnM a идентично a
returnM a = a
-- bindM a f идентично f a
bindM a f = f a
showM a = showVal a
-- Если заменить в коде интерпертатора все функции *M и конструкторы типа M * на их значение, то функция
-- interprete упростится до следующей (слабо отличающейся от реализации на Nemele, которую приводил Влад)
-- interprete :: Term -> Environment -> Value
-- interprete (Var x) e = searchFor x e
-- interprete (Constant i) e = Num i
-- interprete (Add x y) e = add (interprete x e) (interprete y e)
-- interprete (Apply f a) e = apply (interprete f e) (interprete a e)
-- interprete (Lambda x v) e = Fun (\a -> interprete v ((x,a):e))
-- Вычислив test term0 в интерпретаторе Хаскела получим ожидаемый результат "42"
-- Main> test term0
--"42"
--Main> test term1
--"function"
--Main> test (Apply (Constant 1) (Constant 2))
--"<wrong>"
-- основной код интерпретатора остался без измененийtype Name = String
data Term = Var Name
| Constant Int
| Add Term Term
| Lambda Name Term
| Apply Term Term
data Value = Wrong
| Num Int
| Fun (Value -> M Value)
type Environment = [(Name, Value)]
showVal :: Value -> String
showVal Wrong = "<wrong>"
showVal (Num i) = show i
showVal (Fun f) = "function"
interprete :: Term -> Environment -> M Value
interprete (Var x) environment = searchFor x environment
interprete (Constant i) environment = returnM (Num i)
interprete (Add x y) environment = bindM x_value
(\a ->
bindM y_value
(\b -> add a b))
where
x_value = (interprete x environment)
y_value = (interprete y environment)
interprete (Apply function argument) environment = bindM function_value
(\a ->
bindM argument_value
(\b -> apply a b))
where
function_value = (interprete function environment)
argument_value = (interprete argument environment)
interprete (Lambda x v) environment = returnM (Fun (\a -> interprete v ((x,a) : environment)))
searchFor :: Name -> Environment -> M Value
searchFor x [] = returnM Wrong
searchFor x ((y,b) : environment) = if x ==y
then returnM b
else searchFor x environment
add :: Value -> Value -> M Value
add (Num x) (Num y) = returnM (Num (x+y))
add x y = returnM Wrong
apply :: Value -> Value -> M Value
apply (Fun function) argument = function argument
apply function argument = returnM Wrong
test :: Term -> String
test term = showM (interprete term [])
term0 = (Apply (Lambda "x" (Add (Var "x") (Var "x")))
(Add (Constant 10) (Constant 11)))
term1 = (Lambda "x" (Add (Var "x") (Var "x")))
-- добавим вывод ошибок в наш интерпретатор
-- значение может быть либо успешным либо ошибкойdata M a = Success a | Error String
returnM a = Success a
-- определяем bindM для успешной и ошибочной ситуации
bindM (Success a) f = f a
bindM (Error s) f = Error s
-- определяем showM аналогично bindM
showM (Success a) = "Success : " ++ showVal a
showM (Error s) = "Error : " ++ s
-- добавляем новую функцию в нашу монаду - errorM
errorM s = Error s
-- и заменяем все вхождения "returnM Wrong" на соответствующий вызов "errorM"
-- таких мест не много
-- searchFor x [] = returnM Wrong
-- add x y = returnM Wrong
-- apply function argument = returnM Wrong
-- эти функции будут выглядеть следующим образом
-- searchFor x [] = errorM("unbound variable: " ++ x)
-- add x y = errorM("should be numbers : " ++ showVal x ++ "," ++ showVal y)
-- apply function argument = errorM("should be a function : " ++ showVal function
-- и результат выполнения проверок
--Main> test term0
--"Success : 42"
--Main> test term1
--"Success : function"
--Main> test (Apply (Constant 1) (Constant 2))
--"Error : should be a function : 1"
-- Как утверждает Вадлер,
-- без использования монад,
-- возможный вариант обработки ошибок был бы выброс исключений
-- или continuation passingtype Name = String
data Term = Var Name
| Constant Int
| Add Term Term
| Lambda Name Term
| Apply Term Term
data Value = Wrong
| Num Int
| Fun (Value -> M Value)
type Environment = [(Name, Value)]
showVal :: Value -> String
showVal Wrong = "<wrong>"
showVal (Num i) = show i
showVal (Fun f) = "function"
interprete :: Term -> Environment -> M Value
interprete (Var x) environment = searchFor x environment
interprete (Constant i) environment = returnM (Num i)
interprete (Add x y) environment = bindM x_value
(\a ->
bindM y_value
(\b -> add a b))
where
x_value = (interprete x environment)
y_value = (interprete y environment)
interprete (Apply function argument) environment = bindM function_value
(\a ->
bindM argument_value
(\b -> apply a b))
where
function_value = (interprete function environment)
argument_value = (interprete argument environment)
interprete (Lambda x v) environment = returnM (Fun (\a -> interprete v ((x,a) : environment)))
searchFor :: Name -> Environment -> M Value
searchFor x [] = errorM("unbound variable: " ++ x)
searchFor x ((y,b) : environment) = if x ==y
then returnM b
else searchFor x environment
add :: Value -> Value -> M Value
add (Num x) (Num y) = returnM (Num (x+y))
add x y = errorM("should be numbers : " ++ showVal x ++ "," ++ showVal y)
apply :: Value -> Value -> M Value
apply (Fun function) argument = function argument
apply function argument = errorM("should be a function : " ++ showVal function)
test :: Term -> String
test term = showM (interprete term [])
term0 = (Apply (Lambda "x" (Add (Var "x") (Var "x")))
(Add (Constant 10) (Constant 11)))
term1 = (Lambda "x" (Add (Var "x") (Var "x")))
-- Добавим к выводу ошибок еще и позицию в которой ошибка была найдена.
--Пусть Position будет типом, который будет определять позицию ошибки в тексте
-- допустим, номер линии
-- Расширим тим данных Term дополнительным конструктором,
-- который будет определять позицию
-- data Term = ... | At Position Term
-- например конструкция (At p (Apply t (At q u))) означает, что
-- p это позиция терма (Apply t (At q u))
-- q это позиция части терма u
-- для удобства определения позиции создадим новый тип
-- теперь позицию можно будет определять как
-- (Apply (Constant 0) (At (Pos 4) (Var "x")))
-- терм (Var "x") будет находится на позиции 4data Position = Pos Int--Переопределяем функцию show, чтобы была возможность выводить позицию на экранinstance Show Position where
show (Pos i) = show i
-- Мы определим новую монаду , которая принимает в качестве параметра позицию,
-- которая используется при выведении ошибкиtype M a = Position -> E a
-- игногируем позицию
returnM a = \p -> returnE a
-- добавляем позицию в строку сообщения об ошибке
errorM s = \p -> errorE (show p ++ ": " ++ s)
-- передаем позицию в агрумент и функцию
-- `bindE` - инфиксаня форма bindE
bindM m k = \p -> m p `bindE` (\x -> k x p)
-- позиция по умолчанию - 0
showM m = showE (m pos0)
pos0 = Pos 0
-- эта функция используется для изменения позиции.
-- она получает на вход новую позицию и монадическое значение старой позиции
-- и возвращает новое значение позиции завернутое в монаду
resetP :: Position -> M x -> M x
resetP q m = \p -> m q
-- использовавшуюся в предыдущем примере монаду преименовываем в E
-- и точно таким же образом переименовываем все ее методы.data E a = Success a | Error String
returnE a = Success a
bindE (Success a) f = f a
bindE (Error s) f = Error s
showE (Success a) = "Success : " ++ showVal a
showE (Error s) = "Error : " ++ s
errorE s = Error s
-- осталось совсем чуть чуть. сделать так, чтобы интерпретатор мог обрабатывать At термы
-- в функцию interprete добавляем следующую строку
-- interprete (At p t) e = resetP p (interprete t e)
-- она будет менять значение позиции на каждом терме At
-- Больше никаких изменений не требуется.
--То есть все изменения(не учитываем добавленный код) свелись к переименовыванию конструктора типа монады E и ее методов
-- Далее слово Вадлеру (переводить совсем уж лениво)
-- Without monads, or a similar technique, this modification would be far more tedious.
-- Each clause of the interpreter would be need to rewritten
-- to accept the current position as an additional parameter,
-- and to pass it on as appropriate parameter at each recursive call
-- In an impure language , this modification is not quite so easy.
-- One method is to use a state variable that contains a stack of positions
-- Care must be taken to maintain the state property : push a position onto the stack
-- and pop a position off the stack when leaving it.
-- Ну и тестовый пример для запуска в интерпретаторе Хаскела
--Main> test (Apply (Constant 0) (At (Pos 4) (Var "x")))
--"Error : 4: unbound variable: x"type Name = String
data Term = Var Name
| Constant Int
| Add Term Term
| Lambda Name Term
| Apply Term Term
| At Position Term
data Value = Wrong
| Num Int
| Fun (Value -> M Value)
type Environment = [(Name, Value)]
showVal :: Value -> String
showVal Wrong = "<wrong>"
showVal (Num i) = show i
showVal (Fun f) = "function"
interprete :: Term -> Environment -> M Value
interprete (Var x) environment = searchFor x environment
interprete (Constant i) environment = returnM (Num i)
interprete (Add x y) environment = bindM x_value
(\a ->
bindM y_value
(\b -> add a b))
where
x_value = (interprete x environment)
y_value = (interprete y environment)
interprete (Apply function argument) environment = bindM function_value
(\a ->
bindM argument_value
(\b -> apply a b))
where
function_value = (interprete function environment)
argument_value = (interprete argument environment)
interprete (Lambda x v) environment = returnM (Fun (\a -> interprete v ((x,a) : environment)))
interprete (At p t) e = resetP p (interprete t e)
searchFor :: Name -> Environment -> M Value
searchFor x [] = errorM("unbound variable: " ++ x)
searchFor x ((y,b) : environment) = if x ==y
then returnM b
else searchFor x environment
add :: Value -> Value -> M Value
add (Num x) (Num y) = returnM (Num (x+y))
add x y = errorM("should be numbers : " ++ showVal x ++ "," ++ showVal y)
apply :: Value -> Value -> M Value
apply (Fun function) argument = function argument
apply function argument = errorM("should be a function : " ++ showVal function)
test :: Term -> String
test term = showM (interprete term [])
term0 = (Apply (Lambda "x" (Add (Var "x") (Var "x")))
(Add (Constant 10) (Constant 11)))
term1 = (Lambda "x" (Add (Var "x") (Var "x")))
Здравствуйте, lomeo, Вы писали:
L>Почему опять трудится должен я?
Потому что ты вступился за бездакозательное заявление.
L>Потрудись перечитать мой ответ. Что тебе в нём непонятно?
В нем нет ответа на мои вопросы. В частности я просил показать монады в C# и объяснить зачем они вообще нужны в этом фзыке.
VD>>Или то основание, что люди подглядели общую идею в Хаскеле где ее реализация была сделана через монады достаточно чтобы считать что в C# появились монады?
L>Нет, конечно, при чём тут вообще это?
При том что единственная разумная мысль в ваших с ИвелЧилдом рассуждениях была ссылка на фразу о том, что идея LINQ навеяна квэри-компрехеншоном из Хаскеля.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Ты меня извини, но у меня даже нет времени как следует разбираться с приведенным тобой кодо. Да и желания тоже нет, так как код испишрен однобуквенными идентификаторами до смысла которых нужно догадваться. Продираться сквозь эту криптографию к тому же в плохо знакомом мне языке, да еще и смачно смазанном этими самыми монадами я не рескну, даже при наличии коменатриев.
Темболее мне не хочется писать пдобную груду кода.
Прицитпиальных проблем повторить пдобную фигню на Немерле я не вижу. Если ты видишь здесь проблемы, то будь добр выдели их в коротком примере и опиши как следует, а я тогда объясню как я тоже самое сделаю без монад на Немерле. ОК?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, lomeo, Вы писали:
VD>>Именно это я имею в виду. Так будет прямой ответ (да/нет)?
L>Да (в смысле, прямой ответ — да).
Этого достаточно. Далее остается применить прицип Оккама.
L> Твоё решение, например, более легкое для твоего понимания. Это что нибудь меняет?
Естественно. Я не фанат функциональщик который будет делать вид, что все очевидно там где все запутанно. Таких как ты найдутся еденицы, такик как я подавляющее больинство. Именно от того ФЯ и сидят в заднице. Они делались людми с мягко говоря сильно отличающейстя психикой.
L> Легкость в, повторю, первоначальном понимании по твоему является наиважнейшим и единственным фактором при выборе решения?
При выборе языка. При принятии решения возиться с ним или бросить. Да и вообще при принятии решений. Из двух решений всегда надо выбрить более простой и понятное если коенчнь оно подходит. Тут я с тов. Оккамом совершенно согласен.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, lomeo, Вы писали:
L>Как программист пишет код — хоть на голове, это его личное дело. А вот результат ничем не будет отличаться от императивного кода на другом языке. КАК это представлено внутри — без разницы. Поскольку realworld реально не используется — мы получим обычное последовательное (читай императивное) исполнение кода безо всяких realworld.
Разница огромна. Разница в том, что булшит с realworld из серии "это нужно запомнить" и поймут такие решения (точнее даже заходят понимать) далеко не все (точнее мало кто).
L>Что тебя смущает, не пойму? Выглядит код как императивный, компилируется и работает как императивный, что ещё надо то?
VD>>Если бы такое "уменьшение" было бы благом, то в Хаскеле даже числа были бы перечислениями объявленными в каком-нить модуле.
L>Не придумывай. Дело не в том, что уменьшение не благо, а в том, что это просто невозможно. Во всём остальном числа (целые) ведут себя как обычные перечисления.
От, блин, а мужики то и не знали. Арабы хрен знает сколько лет назад придумали позиционную систему счисления и пользуются ее. Описываенся она на раз. А у Хаскеля идеологические проблемы. Впроче, как всегда. Вот по этому я и говорию, что это интеллектуальное извращение и самообман. Попытка отгородиться от окружающего мира шорами.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.