Что делает оператор Haskell?
прохождение документации Haskell всегда немного больно для меня, потому что вся информация, которую вы получаете о функции, часто не более чем: f a -> f [a] что может означать любое количество вещей.
как и в случае .
все, что мне дано, это:(<|>) :: f a -> f a -> f a и вот это "ассоциативная бинарная операция"...
при осмотре Control.Applicative я узнаю, что он делает, казалось бы, несвязанные вещи, в зависимости от по реализации.
instance Alternative Maybe where
empty = Nothing
Nothing <|> r = r
l <|> _ = l
ок, так что он возвращается вправо, если нет левого, в противном случае он возвращается влево, попался.. Это заставляет меня поверить, что это оператор" влево или вправо", что имеет смысл, учитывая его использование | и |историческое использование как "или"
instance Alternative [] where
empty = []
(<|>) = (++)
за исключением того, что здесь он просто вызывает оператор конкатенации списка... Ломая мою идею...
так что же это за функция? Какая от него польза? Где это вписывается в грандиозную схему вещи?
4 ответов:
обычно это означает "выбор" или "параллель" в этом
a <|> b- Это либо "выбор"aилиbилиaиbвыполняться параллельно. Но давайте вернемся назад.на самом деле, нет никакого практического смысла в операциях в объявлениях типа
(<*>)или(<|>). Эти операции получают значение двумя способами: (1) через законы и (2) через экземпляры. Если мы не говорим о особенности экземплярAlternativeтогда только (1) Доступно для интуитивный смысл.так что "ассоциативный" означает, что
a <|> (b <|> c)это то же самое, что(a <|> b) <|> c. Это полезно, Так как это означает, что мы заботимся только о последовательность вещей, прикованных вместе с(<|>), а не их "дерево".другие законы включают идентичность с
empty. В частности,a <|> empty = empty <|> a = a. В нашей интуиции с "выбором" или "параллелью" эти законы читаются как "A или (что-то невозможное) должно быть"или" a рядом (пустой процесс) - это просто a". Оно указывает, чтоemptyэто какой-то" режим отказа " дляAlternative.есть и другие законы, как
(<|>)/emptyвзаимодействовать сfmap(отFunctor) илиpure/(<*>)(отApplicative), но, пожалуй, лучший способ продвинуться вперед в понимании смысла(<|>)это изучить очень распространенный пример типа, который создает экземплярыAlternative: aParser.если
x :: Parser Aиy :: Parser Bзатем(,) <$> x <*> y :: Parser (A, B)анализxа тоyв последовательности. В отличие от этого,(fmap Left x) <|> (fmap Right y)анализ илиxилиy, начиная сx, чтобы попробовать оба возможных разбора. Другими словами, это указывает на филиала в вашем дереве разбора, выбор или параллельный разбор Вселенной.
(<|>) :: f a -> f a -> f aна самом деле говорит вам, довольно много, даже без учета законовAlternative.это занимает два
f aзначения, и должен дать один обратно. Поэтому ему придется как-то комбинировать или выбирать из своих входов. Это полиморфный типa, Так что он будет совершенно не в состоянии проверить все значения типаaможет быть внутриf a; это означает, что она не могу сделать "объединение" путем объединенияaзначения, поэтому он должен к нему чисто в термины любой структуры конструктора типаfдобавляет.имя тоже немного помогает. Какое-то" или "- это действительно расплывчатое понятие, которое авторы пытались обозначить именем" Альтернатива "и символом"".
теперь, если у меня есть два
Maybe aзначения и я должен объединить их, что я могу сделать? Если они обаNothingЯ есть вернутьсяNothingдля созданияa. Если хотя бы один из них-этоJust ...я могу вернуться один из моих входов как есть, или я могу вернутьNothing. Есть очень мало функций, которые даже возможно С типомMaybe a -> Maybe a -> Maybe a, и для класса, чье имя является "альтернативным", данное довольно разумно и очевидно.как насчет объединения двух
[a]значения? Здесь больше возможных функций, но на самом деле это довольно очевидно, что это может сделать. И название "альтернатива" дает вам хороший намек на то, что это, вероятно, будет предоставил вы знакомы со стандартной интерпретацией" недетерминизма " списка монад/аппликативных; если вы видите[a]как "недетерминированныеa" С набором возможных значений, то очевидный путь для "объединения двух недетерминированныхaзначения "таким образом, что может заслуживать название "альтернатива", чтобы произвести недетерминированныйaкоторое может быть любым из значений с любого из входов.и для парсеров; объединение двух Парсеры имеют две очевидные широкие интерпретации, которые приходят на ум; либо вы создаете парсер, который будет соответствовать тому, что делает первый, а затем то, что делает второй, или вы создаете парсер, который соответствует или что делает первая или что делает второй (есть, конечно, тонкие детали каждого из этих вариантов, которые оставляют место для вариантов). Учитывая название "альтернатива", интерпретация " или " кажется очень естественной для
<|>.так, видно из достаточно высокий уровень абстракции, эти операции do все "делают то же самое". Класс type действительно предназначен для работы на том высоком уровне абстракции, где все эти вещи "выглядят одинаково". Когда я работаю на одном известном экземпляре, я просто думаю о
<|>операции, а именно то, что он делает для этого конкретного типа.
интересный пример
AlternativeЭто не парсер или MonadPlus-как вещьConcurrently, очень полезный тип отasyncпакета.на
Concurrently,empty- это вычисление, которое продолжается вечно. И(<|>)выполняет свои аргументы одновременно, возвращает результат первого, который завершает, и отменяет другой.
эти кажется очень разные, но считаю:
Nothing <|> Nothing == Nothing [] <|> [] == [] Just a <|> Nothing == Just a [a] <|> [] == [a] Nothing <|> Just b == Just b [] <|> [b] == [b]Так... это на самом деле очень, очень как, даже если реализация выглядит по-разному. Единственное реальное различие здесь:
Just a <|> Just b == Just a [a] <|> [b] == [a, b]A
Maybeможет содержать только один значение (или ноль, но не любой другой суммы). Но эй, если бы они оба были одинаковых, зачем вам нужны два разных типа? Все дело в том, что они разные, вы знаете, быть разными.В целом,реализация может выглядеть совершенно по-другому, но на самом деле они очень похожи.
Comments