继续获取(使用FlexibleContexts允许此操作)简单Haskell函数中的错误

时间:2017-04-06 01:41:32

标签: haskell monads state-monad

我正在玩Haskell monad并且我一直在收到一个我似乎无法解决的错误。我的代码段使用状态Monad将字符串中的前两个字符添加到一起,并将它们作为状态的一部分返回。我的"放" line一直给我错误:

* Non type-variable argument in the constraint: MonadState [a] m
  (Use FlexibleContexts to permit this)
* When checking the inferred type
    testH :: forall (m :: * -> *) a. MonadState [a] m => [a] -> m [a]

我该如何解决这个问题?扩展语言不是一种选择,我只需要知道如何更改代码以使其工作

test xs = 
 runState (testH (tail xs)) ((head xs):[])

testH xs =
 do
  a <- get 
  put ((head xs):a)
  b <- get
  return b

1 个答案:

答案 0 :(得分:1)

您可以通过启用FlexibleContexts建议,或者通过更改功能来处理比列表更通用的内容来解决此问题。

问题在于Haskell不允许在上下文中使用非类型变量。如果你写出你的功能类型(你应该做什么),你得到

testH :: (Monad m,MonadState [a] m) => [a] -> m [a]

这意味着它是一个函数,它接受一个值列表并在某些monad中返回一个动作,该动作能够保持与输入相同类型的值列表的状态。不幸的是,上下文中的[a]位是无效的Haskell,因为它有一个非类型变量的东西(即列表类型构造函数)。

这里最好的解决方案是启用扩展程序,允许在上下文中使用非类型变量。它没有危险,它只是放松了标准。实际上,多参数类型类(例如MonadState)不是有效的Haskell,因此无论您是否喜欢,您已经在使用语言扩展。

如果这不是一个选项,您可以将其更改为(Monad m,SomeTypeclass f,MonadState (f a) m),并重写您的函数以使用遵循您选择的SomeTypeclass的任何构造函数。这将从类型中删除列表类型构造函数,并允许代码在没有FlexibleContexts的情况下工作。