我正在努力学习Haskell,所以我想我会潜入并尝试一个monad。请参阅下面的我对Calc的实现。这类似于State monad,除了state始终是用于缓存结果的Map。每个Calc都有自己的GUID(尚未实现),用作从地图中检索缓存值的键。
import qualified Data.Map as Map
import Control.Monad
import Data.Dynamic
type CalcId = Int
type Ctx = Map.Map CalcId Dynamic
data Calc a = Calc { eval :: Ctx -> (a, Ctx),
guid :: CalcId }
instance Monad Calc where
(>>=) :: Calc a -> (a -> Calc b) -> Calc b
c1 >>= f = Calc {eval=c2Eval, guid=c2Id}
where c2Id = 1 -- need a way of generating a GUID. add later.
c2Eval = \ctx ->
case (Map.lookup c2Id ctx >>= fromDynamic) :: Maybe b of
Just c2Val ->
(c2Val, ctx)
Nothing ->
let (c1Val, ctx') = eval c1 ctx
c2 = f c1Val
(c2Val', _) = eval c2 ctx'
ctx'' = Map.insert c2Id (toDyn c2Val') ctx'
in (c2Val', ctx'')
此代码可能存在许多问题。但是现在我真的很想让它编译。编译器错误如下;
No instance for (Typeable b1) arising from a use of `fromDynamic'
Possible fix:
add (Typeable b1) to the context of
an expression type signature: Maybe b1
or the type signature for >>= :: Calc a -> (a -> Calc b) -> Calc b
In the second argument of `(>>=)', namely `fromDynamic'
In the expression: (Map.lookup c2Id ctx >>= fromDynamic) :: Maybe b
In the expression:
case (Map.lookup c2Id ctx >>= fromDynamic) :: Maybe b of {
Just c2Val -> (c2Val, ctx)
Nothing
-> let
(c1Val, ctx') = ...
....
in (c2Val', ctx'') }
No instance for (Typeable b) arising from a use of `toDyn'
Possible fix:
add (Typeable b) to the context of
the type signature for >>= :: Calc a -> (a -> Calc b) -> Calc b
In the second argument of `Map.insert', namely `(toDyn c2Val')'
In the expression: Map.insert c2Id (toDyn c2Val') ctx'
In an equation for ctx'':
ctx'' = Map.insert c2Id (toDyn c2Val') ctx'
答案 0 :(得分:5)
问题在于,对于动态值,事物需要成为可键入类的成员。你的下一个问题是你的monad只能用于打字。你的第三个问题是,你不能把它变成monad,因为monads必须能够包含任何东西。看看restricted monads。