我有一個嵌套的或者與不同的錯誤類型,看起來像:嵌套Eithers不同的錯誤類型
Either e1 (Either e2 a)
而且我想,做類似的功能:
Either e1 (Either e2 a) -> Either e2 a
更多一般來說,有沒有一種類型符合這種模式?
我有一個嵌套的或者與不同的錯誤類型,看起來像:嵌套Eithers不同的錯誤類型
Either e1 (Either e2 a)
而且我想,做類似的功能:
Either e1 (Either e2 a) -> Either e2 a
更多一般來說,有沒有一種類型符合這種模式?
你所要求的並不是真的有意義。讓我們來看看你的函數的類型:
f :: Either e1 (Either e2 a) -> Either e2 a
假設這個函數是總(因爲絕大多數的Haskell函數真的應該是),我們需要生產Either e2 a
類型的值任何輸入類型爲Either e1 (Either e2 a)
。要嘗試並實現這一點,讓我們考慮所有的「形狀」的輸入可以進來
原來該類型Either e1 (Either e2 a)
的值可以有三種可能的形狀:
Left _
Right (Left _)
Right (Right _)
底部的兩個形狀很容易處理。事實上,我們可以在任何Right
值只映射到本身:
f (Right x) = x
然而,這不處理外Left
情況。我們可以通過寫模式開始:
f (Left x) = ???
在上面的圖案,我們得到一個值,x
,與e1
類型。我們需要生成Either e2 a
類型的值。這意味着我們基本上需要以下類型的功能:
g :: e1 -> Either e2 a
但是等等!這種類型顯然不可能滿足,因爲我們需要一個e2
或一個a
,但我們只有一個e1
。因此,我們不能執行(假設我們不是無限循環或使用error
或undefined
)。我們被卡住了。
不知道你實際上試圖做,很難提供一個很好的解決這個問題。我至少可以提供一些可能性,也許其中一個可能與您的用例有關。
一個簡單的解決方案是提供一種將e1
值映射到e2
的方法。這樣,我們可以將所有錯誤標準化爲e2
。實現這個很容易與either
功能的幫助:
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = either (Left . g) id
您還可以通過應用映射函數到外Either
的左側,然後使用一元join
功能合併兩個這樣做層:
import Data.Bifunctor
f :: (e1 -> e2) -> Either e1 (Either e2 a) -> Either e2 a
f g = join . first g
我們可以處理這將是調整的結果來編碼兩種可能性的另一種方式。我們可以生成一個Either (Either e1 e2) a
類型的值來保存可能的錯誤。這也很容易與either
函數寫:
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f = either (Left . Left) (either (Left . Right) Right)
然而,這可能與更清晰的模式匹配,而不是either
寫:
f :: Either e1 (Either e2 a) -> Either (Either e1 e2) a
f (Left x) = Left (Left x)
f (Right (Left x)) = Left (Right x)
f (Right (Right x)) = Right x
謝謝,你的文章寫得非常好,也幫助我在自己的腦海中回答和澄清這個問題。 爲了澄清,e1和e2與錯誤具有相似的結構,所以我會考慮將e1錯誤映射到e2錯誤,所以解決方案1對我的情況非常適用。 – plint
什麼你問沒有意義除非該功能是部分功能,或者您提供了一些額外的信息。如果外面的價值是「左」呢?那麼你沒有'e2' *或*'a'類型的值,只有'e1'類型,所以你不能構造'E2a'。 –
我明白你想分組錯誤(例如在左邊),以便得到的類型是'Either(e1 e2)a'。但是現在你想要省略某種類型的錯誤。 –
所以你想要一個函數,它會帶來一個錯誤並且不會發生錯誤? – immibis