gpt4 book ai didi

haskell - 将 Monad 表示法转换为 Arrow 表示法

转载 作者:行者123 更新时间:2023-12-03 20:26:08 25 4
gpt4 key购买 nike

我试图理解箭头符号,特别是它如何与 Monads 一起工作。使用 Monads,我可以定义以下内容:

f = (*2)
g = Just 5 >>= (return . f)

gJust 10
我该如何做上述但使用箭头符号?

最佳答案

将你的 Monad 思维转变为 Arrow 思维

翻译成 Arrow 的第一步是从思考 m b 开始。独自思考a -> m b .

有了一个单子(monad),你会写

use x = do
.....
....
doThis = do
....
...

thing = doThis >>= use

而箭头总是有输入,所以你必须这样做
doThis' _ = do
.....
....

然后使用 (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c来自 Control.Monad确实有
thing' = doThis' >=> use
>=>消除 >>= 的不对称性,也就是我们所说的 Monad 的 Kleisli 箭头。

使用 ()输入或“如果我的第一件事真的不是函数怎么办?”

没关系,如果你的 monad 不产生任何东西(就像 putStrLn 不产生任何东西),这只是一个共同问题,那么你只需将它拿到 return () .

如果您的东西不需要任何数据,只需将其设为需要 () 的函数即可。作为论据。

doThis () = 做
……
……

这样,一切都有签名 a -> m b你可以用 >=>链接它们.

箭头有输入有输出,但没有功能

箭头有签名
Arrow a => a b c

这可能不如中缀清楚
Arrow (~>) => b ~> c

但你仍然应该认为它类似于 b -> m c .

主要区别在于 b -> m c你有你的 b作为函数的参数,可以用它做你喜欢的事情,比如 if b == "war" then launchMissiles else return ()但是你不能使用箭头(除非它是 ArrowApply - 请参阅 this question 了解 ArrowApply 为您提供 Monad 功能的原因) - 一般来说,箭头只是做它所做的事情,而不是根据数据切换操作,有点像 Applicative 做的。

将 Monad 转换为箭头
b -> m c 的问题是你不能在实例声明中部分应用它来获得 -> m从中间位,所以给定 b -> m c被称为 Kleisli 箭头, Control.Monad定义 (>>>)这样在所有的包装和展开之后,你得到 f >>> g = \x -> f x >>= g - 但这相当于 (>>>) = (>=>) . (事实上​​, (.) 是为类别定义的,而不是转发组合 >>> ,但我确实说等价!)
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }

instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f) -- composition of Kleisli arrows

instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))

你的榜样,终于

(尝试忽略所有 KleislirunKleisli - 它们只是包装和展开单值 - 当您定义自己的箭头时,它们不是必需的。)

如果我们解开这对 Maybe 意味着什么? , 我们得到等价于 compose
f :: a -> Maybe b
g :: b -> Maybe c
f >>> g :: a -> Maybe c
f >>> g = \a -> case f a of -- not compilable code!
Nothing -> Nothing
Just b -> g b

并且应用(纯)函数的箭头方式是 arr :: Arrow (~>) => (b -> c) -> b ~> c
我会修复 (~->)表示 Kleisli Maybe所以你可以看到它的作用:
{-# LANGUAGE TypeOperators #-}
import Control.Arrow
type (~->) = Kleisli Maybe

g :: Integer ~-> Integer
g = Kleisli Just >>> arr (*2)

给予
ghci> runKleisli g 10
Just 20

点赞 do符号,但有输入和输出。 (GHC)

GHC 等效于 do符号, proc符号,它可以让你做
output <- arrow -< input

你习惯了 output <- monad但现在有 arrow -< input符号。就像 Monads 一样,你不这样做 <-在最后一行,你不要在 proc 中这样做符号要么。

让我们使用尾的 Maybe 版本并从 safe 读取来说明符号(并宣传 safe )。
{-# LANGUAGE Arrows #-}
import Control.Arrow
import Safe

this = proc inputList -> do
digits <- Kleisli tailMay -< inputList
number <- Kleisli readMay -<< digits
arr (*10) -<< number

请注意,我使用了 -<< -< 的变体,它允许您通过将内容放在 <- 的左侧来使用输出作为输入进入 -< 右侧的范围.

显然 this相当于 Kleisli tailMay >>> Kleisli readMay >>> arr (*10) ,但这只是(!)给你的想法。
ghci> runKleisli this "H1234"  -- works
Just 1234
ghci> runKleisli this "HH1234" -- readMay fails
Nothing
ghci> runKleisli this "" -- tailMay fails
Nothing
ghci> runKleisli this "10" -- works
Just 0

所有这些 ()
就像我说的,我们使用 ()如果我们没有输入,就像我们在 Monad 中所做的那样,如果我们不需要输出任何东西,就返回它。

你会看到 ()proc符号示例:
thing = proc x -> do
this <- thing1 -< ()
() <- thing2 -< x
returnA -< this

关于haskell - 将 Monad 表示法转换为 Arrow 表示法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21809457/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com