<input class="submit-btn" name='submit' type="submit" value="Submit">
Вам не хватает добавить имя, чтобы отправить кнопку, чтобы ваше дело Вам не хватает добавить имя, чтобы отправить кнопку, чтобы ваше дело [111] не удалось if (isset([110]
не удалось
Монада по существу задерживается, обрабатывая. При попытке написать код, который имеет побочные эффекты (например, ввод-вывод) на языке, который не разрешает им и только позволяет чистое вычисление, одна уловка состоит в том, чтобы сказать, "Хорошо, я знаю, что Вы не сделаете побочных эффектов для меня, но можно ли вычислить то, что произошло бы, если бы Вы сделали?"
Это - вид обмана.
Теперь, то объяснение поможет Вам понять большое намерение изображения монад, но дьявол находится в деталях. Как точно Вы вычисляете последствия? Иногда, это не симпатично.
Лучший способ дать обзор, как для кого-то привыкшего к императивному программированию должен сказать, что это помещает Вас в DSL, где операции, которые смотрят синтаксически как то, что Вы привыкли к внешней стороне монада, используются вместо этого для создания функции, которая сделала бы то, что Вы хотите, если Вы могли бы (например), записать в выходной файл. Почти (но не действительно), как будто Вы были строительными нормами и правилами в строке, чтобы позже быть eval'd.
Большая часть того, что Вы делаете в программировании весь день, комбинирует некоторые функции вместе для создания больших функций от них. Обычно у Вас нет только функций на Вашей панели инструментов, но также и других вещах как операторы, переменные присвоения и т.п., но обычно Ваша программа комбинирует вместе много "вычислений" к большим вычислениям, которые будут объединены вместе далее.
Монада является некоторым способом сделать это "объединение вычислений".
Обычно Ваш самый основной "оператор" для объединения двух вычислений вместе ;
:
a; b
При высказывании этого, Вы имеете в виду, "сначала делают a
, затем сделайте b
". Результат a; b
в основном снова вычисление, которое может быть объединено вместе с большим количеством материала. Это - простая монада, это - способ расчесать маленькие вычисления к большим. ;
говорит, "делают вещь слева, затем сделайте вещь справа".
Другая вещь, которая может рассматриваться как монада на объектно-ориентированных языках, .
. Часто Вы находите вещи как это:
a.b().c().d()
.
в основном означает, "оценивают вычисление слева и затем называют метод справа на результате этого". Это - другой способ объединить функции/вычисления вместе, немного более сложный, чем ;
. И понятие объединения в цепочку вещей вместе с .
монада, так как это - способ объединить два вычисления вместе к новому вычислению.
Другая довольно общая монада, которая не имеет никакого специального синтаксиса, является этим шаблоном:
rv = socket.bind(address, port);
if (rv == -1)
return -1;
rv = socket.connect(...);
if (rv == -1)
return -1;
rv = socket.send(...);
if (rv == -1)
return -1;
Возвращаемое значение-1 указывает на отказ, но нет никакого реального способа абстрагировать эту проверку ошибок, даже если у Вас есть много вызовов API, которые необходимо объединить этим способом. Это - в основном просто другая монада, которая комбинирует вызовы функции по правилу, "если функция на левых возвратилась-1, действительно возвратите-1 самостоятельно, иначе вызовите функцию справа". Если у нас был оператор >>=
это сделало эту вещь, которую мы могли просто записать:
socket.bind(...) >>= socket.connect(...) >>= socket.send(...)
Это сделало бы вещи более читаемыми и помогло бы абстрагировать наш специальный способ объединить функции, так, чтобы мы не должны были повторять нас много раз.
И существует намного больше способов объединить функции/вычисления, которые полезны как общий шаблон и могут быть абстрагированы в монаде, позволив пользователю монады написать намного более краткий и код разъединения, так как вся бухгалтерия и управление используемыми функциями сделан в монаде.
Например, вышеупомянутое >>=
мог быть расширен, чтобы "сделать проверку ошибок и затем назвать правую сторону на сокете, который мы получили, как введено", так, чтобы мы не должны были явно указывать socket
много времен:
new socket() >>= bind(...) >>= connect(...) >>= send(...);
Формальное определение немного более сложно, так как необходимо волноваться о том, как получить результат одной функции как вход к следующему, если та функция, потребности, которые вводят и так как Вы хотите удостовериться, что функции Вы объединяетесь, вписываются в способ, которым Вы пытаетесь объединить их в своей монаде. Но фундаментальное понятие просто, что Вы формализуете различные способы объединить функции вместе.
Я уверен, что другие пользователи отправят всесторонний, но я нашел это видео полезным до степени, но я скажу, что я все еще не на грани беглости с понятием, таким образом, что я мог (или если) начинают решать проблемы интуитивно с Монадами.
Можно думать о монаде как о C# interface
то, что классы должны реализовать. Это - прагматический ответ, который игнорирует всю категорию теоретическая математика позади, почему Вы хотели бы принять решение иметь эти объявления в своем интерфейсе и игнорируете все причины, почему Вы хотели бы иметь монады на языке, который старается избегать побочных эффектов, но я нашел, что это было хорошим началом как кем-то, кто понимает (C#) интерфейсы.
Прошёл год с тех пор, как я разместил этот вопрос. После публикации я пару месяцев погрузился в Haskell. Мне это очень понравилось, но я отложил это в сторону, когда был готов погрузиться в монады. Я вернулся к работе и сосредоточился на технологиях, которые требовались моему проекту.
А вчера вечером я пришел и перечитал эти ответы. Самое главное , я перечитал конкретный пример C # в текстовых комментариях к видео Брайана Бекмана , о котором кто-то упоминал выше . Это было настолько ясно и поучительно, что я решил разместить это прямо здесь.
Из-за этого комментария я не только чувствую, что понимаю в точности , что такое монады… Я понимаю, что на самом деле написал некоторые вещи на C #, которые являются монадами… или по крайней мере очень близко, и стремятся решить те же проблемы.
Итак, вот комментарий - это прямая цитата из комментария здесь сильвана :
Это довольно круто. Хотя это немного абстрактно. Я могу представить себе людей , которые не знают, какие монады уже озадачены, из-за отсутствия реальных примеров.
Так что позвольте мне подчиниться, и для большей ясности я сделаю пример на C #, даже если он будет выглядеть некрасиво. Я добавлю эквивалентный Haskell в конце и покажу вам крутой синтаксический сахар Haskell, в котором , IMO, монады действительно начинают приносить пользу.
Хорошо, одна из простейших монад называется "Может быть, монада" в Haskell. В C # тип Maybe называется
Nullable
. По сути, это крошечный класс, который просто инкапсулирует концепцию значения, которое либо допустимо и имеет значение, либо является "нулевым" и не имеет значения.Полезно вставить в монаду для комбинирования значений этого типа понятие отказа. Т.е. мы хотим иметь возможность просматривать несколько значений, допускающих значение NULL, и возвращать
null
, как только любое из них становится нулевым. Это может быть полезно, если вы, например, ищете множество ключей в словаре или что-то в этом роде, и в конце вы хотите обработать все результаты и как-то их объединить, но если ни один из ключей отсутствует в словаре, вы хотите вернутьnull
для всего .Было бы утомительно вручную проверять каждый поиск дляnull
и возврата, поэтому мы можем скрыть эту проверку внутри оператора привязки (который является своего рода точкой монады, мы скрываем бухгалтерский учет в операторе связывания, что упрощает использование кода, поскольку мы можем забыть о деталях).Вот программа, которая мотивирует все это (я определю
Bind
позже, это просто для того, чтобы показать вам, почему это приятно).class Program { static Nullable
f () {return 4; } static Nullable g () {return 7; } статический Nullable h () {return 9; } static void Main (string [] args) { Nullable z = f () .Bind (fval => g (). Bind (gval => h ()). Bind (hval => new Nullable (fval + gval + hval )))); Console.WriteLine ( "z = {0}", z.HasValue? Z.Value.ToString (): "null"); { {1}} Console.WriteLine ("Нажмите любую клавишу, чтобы продолжить ..."); Console.ReadKey (); } } Теперь проигнорируйте на мгновение, что это уже поддерживается для выполнения этого для
Nullable
в C # (вы можете добавить целые числа, допускающие значение NULL, и вы получите null, если любой из них имеет значение NULL ). Давайте представим, что такой возможности нет, и что это просто определяемый пользователем класс без особой магии. Дело в том, что мы можем использовать функциюBind
, чтобы привязать переменную к содержимому нашегоNullable
значения, а затем сделать вид, что нет ничего странного , и используйте их как обычные целые числа и просто складывайте их вместе.Мы оборачиваем результат в конец, допускающий значение NULL, и этот допускающий значение NULL будет либо иметь значение NULL (если любое изf
,g
или] h
возвращает значение null), либо оно будет результатом суммированияf
,g
иh
вместе. (это аналог того, как мы можем привязать строку в базе данных к переменной в LINQ и делать с ней что-нибудь, зная, что операторBind
будет гарантировать, что в переменную будут передаваться только допустимые значения строки ).Вы можете поиграть с этим и изменить любой из
f
,g
,иh
, чтобы вернуть null, и вы увидите, что все это вернет null.Очевидно, что оператор связывания должен выполнить эту проверку за нас и вернуть значение null, если он встречает нулевое значение, а в противном случае передать по значению внутри
Nullable
в лямбду.Вот оператор
Bind
:public static Nullable Bind (this Nullable a, Func > f) {{ 1}} где B: struct , где A: struct { return a.HasValue? f (a.Value): null; }
Типы здесь такие же, как в видео. Для этого требуется
M a
(Nullable
в синтаксисе C # для этого случая) и функция отa
до {{1 }}M b
(Func >
в синтаксисе C #) и возвращаетM b
(Обнуляемый
).Код просто проверяет, содержит ли обнуляемый объект значение, и если да, то извлекает его и передает в функцию, иначе он просто возвращает null. Это означает, что оператор
Bind
будет обрабатывать всю логику проверки на нуль за нас. Если и только если значение, которое мы вызываемBind
, не равно нулю, то это значение будет "передано" лямбда-функции , иначе мы выйдем из строя раньше и все выражение равно нулю.Это позволяет коду, который мы пишем с использованием монады, быть полностью свободным от этого поведения проверки нуля, мы просто используемBind
и получаем переменную, привязанную к значению внутри монадическое значение (fval
,gval
иhval
в примере кода), и мы можем безопасно использовать их в знание того, чтоBind
позаботится о том, чтобы проверить их на нуль, прежде чем передаст их.Есть и другие примеры того, что вы можете делать с монадой. Для примера вы можете заставить оператор
Bind
заботиться о входном потоке символов и использовать его для написания комбинаторов синтаксического анализатора. Тогда каждый комбинатор синтаксического анализатора может полностью игнорировать такие вещи, как обратное отслеживание, сбои синтаксического анализатора и т. Д., И просто объединять меньшие синтаксические анализаторы вместе, как будто что-то никогда не пойдет не так, безопасно зная, что умная реализацияBind
сортирует всю логику, стоящую за трудными битами. Позже, возможно, кто-то добавит протоколирование в монаду, , но код, использующий монаду, не изменится, потому что вся магия происходит в определении оператораBind
, остальная часть кода не изменилась.Наконец, вот реализация того же кода в Haskell (
-
начинается строкой комментария).- Вот тип данных, либо ничего, либо "Просто" значение - это в стандартной библиотеке data. Может быть a = Nothing | Just a - оператор связывания для Nothing Nothing >> = f = Nothing - оператор связывания для Just x Just x >> = f = fx - «единица», называемая «return» return = Just - образец код с использованием лямбда-синтаксиса , который показал Брайан z = f >> = (\ fval -> g >> = (\ gval -> ) h >> = (\ hval -> return (fval + gval + hval)))) - следующее в точности то же, что и три строки выше z2 = do fval <- f gval <- g hval <- h return (fval + gval + hval)
Как вы можете увидеть красивую нотацию
do
в конце, которая делает его похожим на прямой императивный код . И действительно, это сделано намеренно. Монады можно использовать для инкапсуляции всего полезного в императивном программировании (изменяемое состояние, ввод-вывод и т. Д.) И использовать этот красивый синтаксис, подобный императиву , но за кулисами , это всего лишь монады и умная реализация оператора связывания! Замечательно то, что вы можете реализовать свои собственные монады, реализовав>> =
иreturn
. И если вы это сделаете, эти монады также смогут использовать нотациюdo
, что означает, что вы можете писать на своих маленьких языках, просто определение двух функций!