gpt4 book ai didi

haskell - 了解 Monad Transformer 类型签名

转载 作者:行者123 更新时间:2023-12-01 22:26:17 24 4
gpt4 key购买 nike

我目前正在处理 monad 转换器并试图真正理解类型签名,但我遇到了一些困惑。让我们使用以下堆栈进行讨论:

newtype Stack s m a = Stack { runStack :: ReaderT s (StateT s IO) a }

我试图逐层检查并编写未包装的类型签名,但陷入困境:

newtype Stack s m a = Stack { 
runStack :: ReaderT s (StateT s IO) a }
-- ReaderT s m a
-- s -> m a
-- s -> (StateT s IO) a
-- StateT s m a
-- s -> (s -> IO (a, s)) a

最后一行看起来不像是有效的返回类型签名,我们本质上有一个函数,它接受 s 并返回一个与 a 相对应的函数。 ?

明白内部函数最终计算结果为 Monad,这就是为什么它是 mReaderT r m a ,但它让我的大脑弯曲。

任何人都可以提供任何见解吗?我是否正确分析了这些类型,我只能接受s -> (s -> IO (a, s)) a确实有效吗?

谢谢

最佳答案

您编写的堆栈有点奇怪,因为它的参数化为 m位于左侧,但专门用于 IO在右边,让我们看一下完整的m -参数化变体:

newtype Stack s m a = Stack { runStack :: ReaderT s (StateT s m) a }

现在runStack这里只是一个字段名称,因此我们可以删除它并编写等效的 newtype定义:

newtype Stack s m a = Stack (ReaderT s (StateT s m) a)

我们还有以下库新类型定义,跳过字段名称。我还使用了新的变量,所以我们不会做一些愚蠢的事情,比如混淆两个 a扩展时处于不同范围:

newtype ReaderT r1 m1 a1 = ReaderT (r1 -> m1 a1)
newtype StateT s2 m2 a2 = StateT (s2 -> m2 (a2, s2))

当然,如果我们只对同构的类型感兴趣,那么 newtype 包装器并不重要,所以只需将它们重写为类型别名即可:

type Stack s m a = ReaderT s (StateT s m) a
type ReaderT r1 m1 a1 = r1 -> m1 a1
type StateT s2 m2 a2 = s2 -> m2 (a2, s2)

现在,可以轻松扩展 Stack类型:

Stack s m a
= ReaderT s (StateT s m) a
-- expand ReaderT with r1=s, m1=StateT s m, a1=a
= s -> (StateT s m) a
= s -> StateT s m a
-- expand StateT with s2=s m2=m a2=a
= s -> (s -> m (a, s))
= s -> s -> m (a, s)

正如 @duplode 指出的,没有额外的 a在这里。

直观上这个Stacks 读取(第一个参数)采用 s 类型的初始状态(第二个参数),并返回 m 中的单子(monad)操作(例如 IO )可以返回 a 类型的值以及类型 s 的更新状态.

关于haskell - 了解 Monad Transformer 类型签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55550603/

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