以下代码:
-- tst2.hs - showing successful monadic linkage.
{-
{-
import Protolude
import Control.Monad.Extra (unfoldM)
foo :: Monad m
=> Int
-> m [[Int]]
foo n = evalStateT (traverse nxt [1..n]) 0
where nxt _ = do s <- get
r <- bar s
put $ s + 1
return r
bar :: Monad m
=> Int
-> m [Int]
bar n = unfoldM step n
where step k = return $ if k > 0 then Just (k, k - 1)
else Nothing
main :: IO ()
main = do xs <- foo 3
print xs
工作正常,产生以下输出:
Davids-Air-2:haskell-rl dbanas$ stack runghc tst2.hs
[[],[1],[2,1]]
但是,如果我稍微更改代码:
-- tst3.hs - showing breakage of monadic linkage.
{-
{-
import Protolude
import Control.Monad.Extra (unfoldM)
data Dummy m = Dummy (Int -> m Int)
foo :: Monad m
=> Int
-> Dummy m
-> m [[Int]]
foo n d = evalStateT (traverse nxt [1..n]) 0
where nxt _ = do s <- get
r <- bar s d
put $ s + 1
return r
bar :: Monad m
=> Int
-> Dummy m
-> m [Int]
bar n d = unfoldM step n
where step k = return $ if k > 0 then Just (k, k - 1)
else Nothing
main :: IO ()
main = do xs <- foo 3 $ Dummy (\n -> return n)
print xs
我发现以下编译器错误:
Davids-Air-2:haskell-rl dbanas$ stack runghc tst3.hs
tst3.hs:15:23: error:
⢠Couldn't match type âmâ with âStateT Integer mâ
âmâ is a rigid type variable bound by
the type signature for:
foo :: forall (m :: * -> *). Monad m => Int -> Dummy m -> m [[Int]]
at tst3.hs:(11,1)-(14,16)
Expected type: StateT Integer m [[Int]]
Actual type: m [[Int]]
⢠In the first argument of âevalStateTâ, namely
â(traverse nxt [1 .. n])â
In the expression: evalStateT (traverse nxt [1 .. n]) 0
In an equation for âfooâ:
foo n d
= evalStateT (traverse nxt [1 .. n]) 0
where
nxt _
= do s <- get
....
⢠Relevant bindings include
nxt :: forall p. p -> m [Int] (bound at tst3.hs:16:8)
d :: Dummy m (bound at tst3.hs:15:7)
foo :: Int -> Dummy m -> m [[Int]] (bound at tst3.hs:15:1)
|
15 | foo n d = evalStateT (traverse nxt [1..n]) 0
| ^^^^^^^^^^^^^^^^^^^
结果证明,解决方案非常简单,尽管我花了几个小时来推断:
r <- lift $ bar s d
Davids-Air-2:haskell-rl dbanas$ stack runghc tst3.hs
[[],[1],[2,1]]
我对此有一个理论,希望得到证实:
Monad在中运行
bar
与在中运行的Monad不同
foo
。
具体来说,Monad在
foo公司
是
已解除
在中运行的Monad版本
酒吧
(提升到a
StateT
确切地说,是上下文。)
假使
tst2.hs
如果两者之间没有类型链接
m
s(共个)
foo公司
和
酒吧
),此操作非常有效。
然而,在
tst3.hs
我提供了两者之间的类型链接,迫使它们成为同一个Monad。
这就是编译器抱怨的原因。
我的解决方案有效,只是因为Monad在
foo公司
真的是
已解除
在中运行的版本
酒吧
。
如果这两个单子完全不相关,那么我的解决方案
不
工作
一切都对吗?