为什么 StateT 的这个 Applicative 实例有效?
Why is this Applicative instance for StateT working?
我是 Haskell(和 CS)初学者。我正在努力完成 haskellbook。我正在为 StateT
实现 Applicative
实例,其中 StateT
定义为:
newtype StateT s m a = StateT { runState :: s -> m (a, s) }
书中提到,要为 StateT s m
创建一个 Applicative
实例,我们需要 m
上的 Monad
约束,而不是 Applicative
正如人们所期望的那样。在阅读书中引用的 SO 答案的公认 answer 时,我也得出了相同的结论。
但是,为了更好地理解,我尝试创建一个 Applicative
实例,并在 m
上使用 Applicative
约束,并成功编译。我还在几个例子中尝试过它,它似乎工作正常。有人可以解释一下,这里有什么问题吗?
instance (Applicative m) => Applicative (StateT s m) where
pure a = StateT $ \s -> pure $ (a, s)
(<*>) :: (StateT s m (a -> b)) -> (StateT s m a) -> (StateT s m b)
(StateT smf) <*> (StateT sma) = StateT $ \s -> (f) <$> (smf s) <*> (sma s)
where
f :: (a -> b, s) -> (a, s) -> (b, s)
f (ff, s) = \(a, s) -> (ff a,s)
*StateT> s1 = StateT (\s -> return (4, s))
*StateT> s2 = map (+) s1
*StateT> s3 = StateT (\s -> return (20, s))
*StateT> runState (s2 <*> s3) * 10
(24,10)
*StateT>
EDIT :@Koterpillar 建议我尝试使用状态也被修改的示例进行尝试。我尝试使用 this example. Also, here 是 Monad
约束版本,我认为它的行为也不尽如人意。我认为问题在于各州没有以某种方式联系在一起。如果有人能阐明这个话题,我将不胜感激。
这是 <*>
对于 StateT
应该做的:
- 运行
smf
与初始状态
- 运行
sma
状态来自 smf
- Return这个最终状态
这就是您的代码所做的:
- 运行
smf
与初始状态
- 运行
sma
和初始状态
- Return这个最终状态
换句话说,这个bug就是丢弃smf
引起的状态变化。
我们可以用修改 smf
中的状态的代码来演示这个问题。例如:
s1 = StateT $ \s -> return (const (), s + 1)
s2 = StateT $ \s -> return ((), s)
然后 runState (s1 <*> s2) 0
将 return ((), 1)
与标准实施,但 ((), 0)
与你的。
我是 Haskell(和 CS)初学者。我正在努力完成 haskellbook。我正在为 StateT
实现 Applicative
实例,其中 StateT
定义为:
newtype StateT s m a = StateT { runState :: s -> m (a, s) }
书中提到,要为 StateT s m
创建一个 Applicative
实例,我们需要 m
上的 Monad
约束,而不是 Applicative
正如人们所期望的那样。在阅读书中引用的 SO 答案的公认 answer 时,我也得出了相同的结论。
但是,为了更好地理解,我尝试创建一个 Applicative
实例,并在 m
上使用 Applicative
约束,并成功编译。我还在几个例子中尝试过它,它似乎工作正常。有人可以解释一下,这里有什么问题吗?
instance (Applicative m) => Applicative (StateT s m) where
pure a = StateT $ \s -> pure $ (a, s)
(<*>) :: (StateT s m (a -> b)) -> (StateT s m a) -> (StateT s m b)
(StateT smf) <*> (StateT sma) = StateT $ \s -> (f) <$> (smf s) <*> (sma s)
where
f :: (a -> b, s) -> (a, s) -> (b, s)
f (ff, s) = \(a, s) -> (ff a,s)
*StateT> s1 = StateT (\s -> return (4, s))
*StateT> s2 = map (+) s1
*StateT> s3 = StateT (\s -> return (20, s))
*StateT> runState (s2 <*> s3) * 10
(24,10)
*StateT>
EDIT :@Koterpillar 建议我尝试使用状态也被修改的示例进行尝试。我尝试使用 this example. Also, here 是 Monad
约束版本,我认为它的行为也不尽如人意。我认为问题在于各州没有以某种方式联系在一起。如果有人能阐明这个话题,我将不胜感激。
这是 <*>
对于 StateT
应该做的:
- 运行
smf
与初始状态 - 运行
sma
状态来自smf
- Return这个最终状态
这就是您的代码所做的:
- 运行
smf
与初始状态 - 运行
sma
和初始状态 - Return这个最终状态
换句话说,这个bug就是丢弃smf
引起的状态变化。
我们可以用修改 smf
中的状态的代码来演示这个问题。例如:
s1 = StateT $ \s -> return (const (), s + 1)
s2 = StateT $ \s -> return ((), s)
然后 runState (s1 <*> s2) 0
将 return ((), 1)
与标准实施,但 ((), 0)
与你的。