变量参数(类似printf)函数中的Ambigous类型变量

时间:2015-10-27 06:18:17

标签: haskell

我正在编写一个解释器,我想要一个函数,它接受一个带有普通参数的函数,并将它转换成一个与解释器一起工作的函数。 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相同,但我不知道如何在里面编码它。

1 个答案:

答案 0 :(得分:3)

问题是编译器不能假设MyFunc m (a -> r)没有实例,Int -> Int -> m1 Value适合与m1不同的m:有人可以添加它在一个不同的模块中。这被称为开放世界的假设。

这应该很容易解决

funclist = [
    convert (testfunc1 :: Int -> Int -> m Value)
  ]

(如果需要-XScopedTypeVariables,则无法确定;如果是,请将forall m.添加到funclist签名。