使用自定义类型类键入麻烦

时间:2015-01-15 20:44:37

标签: haskell types monads

在学习Haskell时,我遇到了一些类型的问题。 我有一个名为Stack的类型类,显然应该像堆栈一样。我有一个类型Elem,它只是一个Int或Bool。

现在我希望我的函数获取Stack Elem并对其执行一些操作。结果实际上并不重要,但是我甚至无法获得堆栈的第一个元素,而且我几个小时都没能弄清楚出现了什么问题。

import Control.Monad

data Elem = Number Int | Truth Bool deriving Eq

instance Show Elem where
  show (Number i) = show i
  show (Truth b) = show b

class Stack stack where
  push :: a -> stack a -> stack a
  top :: MonadPlus m => stack a -> m (a,stack a)
  empty :: stack a
  isEmpty :: stack a -> Bool

instance Stack [] where
  push a stack = a:stack
  top stack = if isEmpty stack then mzero else return (head stack, tail stack)
  empty = []
  isEmpty stack = if null stack then True else False

step :: Stack stack => String -> stack Elem -> Maybe (stack Elem)
step ex st = let e1 = top st :: Maybe (Elem, stack Elem)
                 --a1 = fmap fst e1
                 --e2 = top (fmap snd e1)
                 --a2 = fmap fst e2
             in Nothing

我得到的错误是

Playground.hs:22:27:
    Could not deduce (stack ~ stack2)
    from the context (Stack stack)
      bound by the type signature for
                 step :: Stack stack => String -> stack Elem -> Maybe (stack Ele
m)
      at Playground.hs:21:9-65
      `stack' is a rigid type variable bound by
              the type signature for
                step :: Stack stack => String -> stack Elem -> Maybe (stack Elem
)
              at Playground.hs:21:9
      `stack2' is a rigid type variable bound by
               an expression type signature: Maybe (Elem, stack2 Elem)
               at Playground.hs:22:23
    Expected type: stack2 Elem
      Actual type: stack Elem
    Relevant bindings include
      st :: stack Elem
        (bound at Playground.hs:22:9)
      step :: String -> stack Elem -> Maybe (stack Elem)
        (bound at Playground.hs:22:1)
    In the first argument of `top', namely `st'
    In the expression: top st :: Maybe (Elem, stack Elem)

我真的不明白为什么Haskell拒绝这个(甚至拒绝在我的函数中简单地调用top st而我没有尝试指定类型)。

我希望有人可以对此有所了解!

1 个答案:

答案 0 :(得分:1)

正如两位评论者建议的那样,您需要-XScopedTypeVariables

以下代码为我编译:

{-# LANGUAGE ScopedTypeVariables #-}

module Foo where

import Control.Monad

data Elem = Number Int | Truth Bool deriving Eq

instance Show Elem where
  show (Number i) = show i
  show (Truth b) = show b

class Stack stack where
  push :: a -> stack a -> stack a
  top :: MonadPlus m => stack a -> m (a,stack a)
  empty :: stack a
  isEmpty :: stack a -> Bool

instance Stack [] where
  push a stack = a:stack
  top stack = if isEmpty stack then mzero else return (head stack, tail stack)
  empty = []
  isEmpty stack = if null stack then True else False

step :: forall stack . Stack stack => String -> stack Elem -> Maybe (stack Elem)
step ex st = let e1 = top st :: Maybe (Elem, stack Elem)
                 --a1 = fmap fst e1
                 --e2 = top (fmap snd e1)
                 --a2 = fmap fst e2
             in Nothing

我不确定你的意思"无法访问forall语法",但如果你真的想避免它,你也可以写{{1}像这样:

step

你仍然需要step :: Stack stack => String -> stack Elem -> Maybe (stack Elem) step ex (st :: stack Elem) = let e1 = top st :: Maybe (Elem, stack Elem) --a1 = fmap fst e1 --e2 = top (fmap snd e1) --a2 = fmap fst e2 in Nothing