类型中的多个类型参数?

时间:2015-09-18 16:27:00

标签: haskell typeclass

假设我有一个类型类Stack,其中包含一个实例List

class Stack a where
    push :: a -> Integer -> a
    pop :: a -> a
    last :: a -> Integer

data List = Empty | Element Integer List
instance Stack List where
    push list value = Element value list
    pop Empty = error "No elements"
    pop (Element _ list) = list
    last Empty = error "No elements"
    last (Element value _) = value

为了使Stack不限于List值,必须如何定义Integer

-- class Stack (?) where ...
data List a = Empty | Element a (List a)
-- instance Show (List a) where ...

2 个答案:

答案 0 :(得分:8)

考虑使用更高级的类变量。因此:

class Stack s where
    push :: s a -> a -> s a
    pop  :: s a -> s a
    last :: s a -> a

data List a = Empty | Element a (List a)

实例与您编写的内容完全一样(尽管List现在有* -> *而不是*):

instance Stack List where
    push list value = Element value list
    pop Empty = error "No elements"
    pop (Element _ list) = list
    last Empty = error "No elements"
    last (Element value _) = value

这种方法纯粹是Haskell 2010 - 它不需要扩展。

另外,考虑让你的失败可以观察到;例如,将poplast的类型分别更改为Maybe (s a)Maybe a

答案 1 :(得分:6)

在这种情况下,您可以创建一个多参数类:

class Stack a b where
    push :: a -> b -> a
    pop :: a -> a
    last :: a -> b

并用以下内容定义:

instance Stack (List b) b where --You don't need to use `b`, but this make it easier to understand
    push list value = Element value list
    pop Empty = error "No elements"
    pop (Element _ list) = list
    last Empty = error "No elements"
    last (Element value _) = value

请注意,这不是默认(标准化)Haskell功能,您需要将其打开。通过将-XMultiParamTypeClasses-XFlexibleInstances传递给编译器。

或者你可以写:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

在源文件的标题中。

请注意,您为其定义一个实例的b可能有多个a(反之亦然)。这可能使这些类很难使用。比如你写一个Dummy类型:

data Dummy = Dummy

你可以定义:

instance Stack Dummy b where
    push x = const x
    pop = id
    last = const $ error "Dummy object"

现在,这意味着每个可能的Stack都有b个实例,这样您就可以pushpopDummy个对象发送各种内容