簡體   English   中英

Haskell 的 <|> 運算符有什么作用?

[英]What does Haskell's <|> operator do?

瀏覽 Haskell 的文檔對我來說總是有點痛苦,因為你獲得的關於函數的所有信息通常只是: fa -> f [a]這可能意味着任何數量的事情。

<|>函數的情況一樣。

我得到的只是這個: (<|>) :: fa -> fa -> fa並且它是一個“關聯二元運算” ......

在檢查Control.Applicative我了解到它根據實現做了看似無關的事情。

instance Alternative Maybe where
    empty = Nothing
    Nothing <|> r = r
    l       <|> _ = l

好的,所以如果沒有左,它返回右,否則它返回左,明白了..這讓我相信它是一個“左或右”運算符,考慮到它的使用| | 歷史上用作“OR”

instance Alternative [] where
    empty = []
    (<|>) = (++)

除了這里它只是調用列表的連接運算符......打破我的想法......

那么這個函數究竟是什么呢? 它有什么用? 它在宏偉的計划中處於什么位置?

通常它的意思是“選擇”或“並行”,因為a <|> bab的“選擇”,或者ab並行完成。 但是讓我們備份。

實際上,像(<*>)(<|>)這樣的類型類中的操作沒有實際意義。 這些操作的含義有兩種:(1)通過定律和(2)通過實例化。 如果我們不是在談論Alternative特定實例,那么只有 (1) 可用於直觀意義。

所以“關聯”意味着a <|> (b <|> c)(a <|> b) <|> c 這很有用,因為這意味着我們只關心用(<|>)鏈接在一起的事物的順序,而不關心它們的“樹結構”。

其他法律包括身份與empty 特別是, a <|> empty = empty <|> a = a 在我們對“選擇”或“平行”的直覺中,這些定律讀作“a 或(不可能的東西)必須是a”或“a 旁邊(空過程)只是a”。 它表明emptyAlternative某種“失敗模式”。

還有其他關於(<|>) / empty如何與fmap (來自Functor )或pure / (<*>) (來自Applicative )交互的fmap ,但也許是理解(<|>)是檢查實例化Alternative類型的一個非常常見的示例: Parser

如果x :: Parser Ay :: Parser B(,) <$> x <*> y :: Parser (A, B)依次解析xy 相比之下, (fmap Left x) <|> (fmap Right y)解析無論是xy ,與始x ,嘗試兩種可能的解析。 換句話說,它表示您的分析樹中的一個分支、一個選擇或一個平行的分析領域。

(<|>) :: fa -> fa -> fa實際上告訴你很多,即使不考慮Alternative的法則。

它需要兩個fa值,並且必須返回一個。 因此,它必須以某種方式組合或從其輸入中進行選擇。 它在a類型中a多態a ,因此它完全無法檢查fa可能存在的任何類型a值; 這意味着它不能通過組合a值來進行“組合”,因此它必須純粹根據類型構造函數f添加的任何結構來進行。

這個名字也有點幫助。 某種“或”確實是作者試圖用名稱“替代”和符號“<|>”表示的模糊概念。

現在,如果我有兩個Maybe a值並且我必須將它們組合起來,我該怎么辦? 如果它們都是Nothing我將不得不返回Nothing ,無法創建a 如果其中至少一個是Just ...我可以按原樣返回我的輸入之一,或者我可以返回Nothing 很少有函數可以使用類型Maybe a -> Maybe a -> Maybe a ,並且對於名稱為“Alternative”的類,給出的函數非常合理且顯而易見。

結合兩個[a]值怎么樣? 這里有更多可能的功能,但實際上很明顯這可能會做什么。 如果您熟悉列表 monad/applicative 的標准“非確定性”解釋,那么名稱“Alternative”確實可以很好地提示您這可能是什么; 如果您將[a]視為具有可能值集合的“非確定性a ”,那么以一種可能應得“替代”名稱的方式“組合兩個非確定性a值”的顯而易見的方法是產生一個非確定性a可以是來自任一輸入的任何值。

對於解析器; 結合兩個解析器有兩個明顯的廣泛解釋; 要么你生成解析器會匹配第一個做什么,然后第二個做什么,或者你產生一種解析器,匹配要么什么第一呢還是什么,第二做(也有每個選項是假的當然微妙的細節選擇余地)。 鑒於名稱“替代”,“或”解釋對於<|>似乎很自然。

所以,從一個足夠高的抽象層次看出,這些操作“做同樣的事情。” 類型類實際上是為了在這些東西“看起來都一樣”的高抽象層次上操作。 當我在單個已知實例上操作時,我只是認為<|>操作與它對特定類型所做的完全一樣。

一個不是解析器或類似 MonadPlus 的Alternative的有趣示例是Concurrently ,它是async包中非常有用的類型。

對於Concurrentlyempty是一個永遠持續的計算。 And (<|>)並發執行其參數,返回第一個完成的結果,並取消另一個。

這些看起來非常不同,但請考慮:

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只能容納一個值(或零,但不能容納任何其他數量)。 但是,嘿,如果它們都是相同的,為什么需要兩種不同的類型? 他們與眾不同的全部意義在於,你知道,要與眾不同

總之,實現可能看起來完全不同,但它們實際上非常相似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM