我最近寫
do
e <- (Left <$> m) <|> (Right <$> n)
more actions
case e of
Left x -> ...
Right y -> ...
這似乎很尷尬。我知道protolude(和其他一些包)定義
-- Called eitherP in parser combinator libraries
eitherA :: Alternative f => f a -> f b -> f (Either a b)
但即便如此,這一切都感覺有點手動。有沒有一些我沒見過的很好的模式來收緊它?
uj5u.com熱心網友回復:
我剛剛注意到 OP在評論中表達了同樣的想法。無論如何我都會發表我的想法。
Coyoneda 是一個巧妙的技巧,但對于這個特殊問題來說有點過分了。我認為您所需要的只是常規的舊延續。
讓我們將這些命名為...:
do
e <- (Left <$> m) <|> (Right <$> n)
more actions
case e of
Left x -> fx x
Right y -> fy y
然后,我們可以把它寫成:
do
e <- (fx <$> m) <|> (fy <$> n)
more actions
e
這有點微妙——<$>盡管看起來你可能想要使用它,但在此處使用很重要,=<<這樣第一行的結果實際上是稍后執行的一元動作,而不是立即執行的動作。
uj5u.com熱心網友回復:
這個問題想得太多了,但是...
在您的代碼中,每個分支的型別Either可能是不同的,但它們不會逃脫 do-block,因為它們被LeftandRight延續“擦除”。
這看起來有點像存在主義型別。或許我們可以宣告一個型別,它將初始動作和它的延續打包在一起,并給那個型別一個Alternative實體。
實際上,我們不必宣告它,因為在 Hackage 中已經存在這樣的型別:它Coyoneda來自kan-extensions。
data Coyoneda f a where
Coyoneda :: (b -> a) -> f b -> Coyoneda f a
哪個有有用的實體
Alternative f => Alternative (Coyoneda f)
MonadPlus f => MonadPlus (Coyoneda f)
在我們的例子中,“回傳值”本身就是一個 monadic action m,所以我們要處理 type 的值Coyoneda m (m a)wherem a是整個 do-block 的型別。
知道了這一切,我們可以定義以下函式:
sandwich :: (Foldable f, MonadPlus m, Monad m)
=> m x
-> f (Coyoneda m (m a))
-> m a
sandwich more = join . lowerCoyoneda . hoistCoyoneda (<* more) . asum
重新實作原始示例:
sandwich more [Coyoneda m xCont, Coyoneda n yCont]
uj5u.com熱心網友回復:
你也許可以這樣做:
do
let acts = do more actions
(do x <- m; acts; ...) <|> (do y <- n; acts; ...)
我不知道這對你來說是否更好看。
(當然,如果這些more actions系結了許多變數,這不會很好地作業)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/423008.html
標籤:
上一篇:實體電感作為約束
