我正在编写一个解释器,我想要一个函数,它接受一个带有普通参数的函数,并将它转换成一个与解释器一起工作的函数。 E.g:
add :: Monad m => Int -> Int -> m Value
let myadd = convert add :: Monad m => [Value] -> m Value
我创建了一些实际上只有m
具体才能实现的类 - 但是我需要结果仍然是类型m Value
,而不是IO Value
(我需要在2个不同的monad中使用它。)
data Value = VInteger Int deriving (Show)
class MyArg a where
fromValue :: Value -> Maybe a
instance MyArg Int where
fromValue (VInteger a) = Just a
fromValue _ = Nothing
class Monad m => MyFunc m r where
convert :: r -> [Value] -> m Value
instance Monad m => MyFunc m (m Value) where
convert f [] = f
convert _ _ = fail ""
instance (Monad m, MyArg a, MyFunc m r) => MyFunc m (a -> r) where
convert f (arg:rest)
| Just v <- fromValue arg = convert (f v) rest
convert _ _ = fail ""
我有这个功能要转换:
testfunc1 :: Monad m => Int -> Int -> m Value
testfunc1 num num2 = return $ VInteger (num + 10 * num2)
这有效:
main = do
let val = convert (testfunc1 :: Int -> Int -> Maybe Value) [VInteger 3, VInteger 5] :: Maybe Value
print val
然而,这不是:
let val = convert testfunc1 [VInteger 3, VInteger 5] :: Maybe Value
这是我的用例,也不是:
funclist :: Monad m => [ [Value] -> m Value ]
funclist = [
convert testfunc1
]
错误是:
No instance for (GHC.Base.Monad m1)
arising from a use of ‘Main.testfunc1’
The type variable ‘m1’ is ambiguous
在我看来,类型类似乎无法理解转换函数的m
应该与原始函数中的m
相同,但我不知道如何在里面编码它。
答案 0 :(得分:3)
问题是编译器不能假设MyFunc m (a -> r)
没有实例,Int -> Int -> m1 Value
适合与m1
不同的m
:有人可以添加它在一个不同的模块中。这被称为开放世界的假设。
这应该很容易解决
funclist = [
convert (testfunc1 :: Int -> Int -> m Value)
]
(如果需要-XScopedTypeVariables
,则无法确定;如果是,请将forall m.
添加到funclist
签名。