2015-01-15 3 views
1

У меня возникают проблемы с типами при изучении Haskell. У меня есть класс под названием Stack, который, очевидно, должен вести себя как стек. У меня есть тип Elem, который просто является Int или Bool.Тип проблемы с пользовательским typeclass

Теперь я хочу, чтобы моя функция принимала StackElem и выполняла некоторые операции с ней. Результат на самом деле не важен, однако я не могу даже получить первый элемент стека, и я не смог выяснить, что не так в течение нескольких часов.

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 в моей функции без меня, пытаясь определить тип).

Я надеюсь, что кто-то может пролить свет на это!

+4

Компилятор не знает, что 'stack' в типе sig' step' - это тот же 'stack' в' Maybe (Elem, stack Elem) '. Вы ищете 'ScopedTypeVariables', но это означает, что вам нужно будет изменить sig на' step :: forall stack. Stack stack => String -> stack Elem -> Maybe (stack Elem) '. – bheklilr

+0

@bheklilr У меня нет доступа к синтаксису forall. Должно быть возможно каким-то образом получить первый элемент стека в моей функции ?! – Marco

+3

Вы положили '{- # LANGUAGE ScopedTypeVariables # -}' вверху вашего файла? – bheklilr

ответ

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 синтаксиса», но если вы действительно хотите, чтобы избежать этого, вы также можете написать 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 

Вам еще нужно ScopedTypeVariables хотя.

Смежные вопросы