类型 class 中的多个类型参数?
Multiple type parameters in type class?
假设我有一个类型 class 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 ...
在那种情况下你可以做一个多参数class:
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 #-}
在源文件的 header 中。
请注意,您可以为一个 a
定义多个 b
实例(反之亦然)。这会使使用这样的 classes 变得困难。比如说你写了一个 Dummy
type:
data Dummy = Dummy
你可以定义:
instance Stack Dummy b where
push x = const x
pop = id
last = const $ error "Dummy object"
现在这意味着每个可能的 b
都有 Stack
个实例,这样您就可以 push
和 pop
各种东西到 Dummy
objects.
考虑使用更高级的 class 变量。因此:
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 -- 它不需要扩展。
另外,考虑让你的失败变得可观察;例如,将 pop
和 last
的类型分别更改为 return Maybe (s a)
和 Maybe a
。
假设我有一个类型 class 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 ...
在那种情况下你可以做一个多参数class:
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 #-}
在源文件的 header 中。
请注意,您可以为一个 a
定义多个 b
实例(反之亦然)。这会使使用这样的 classes 变得困难。比如说你写了一个 Dummy
type:
data Dummy = Dummy
你可以定义:
instance Stack Dummy b where
push x = const x
pop = id
last = const $ error "Dummy object"
现在这意味着每个可能的 b
都有 Stack
个实例,这样您就可以 push
和 pop
各种东西到 Dummy
objects.
考虑使用更高级的 class 变量。因此:
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 -- 它不需要扩展。
另外,考虑让你的失败变得可观察;例如,将 pop
和 last
的类型分别更改为 return Maybe (s a)
和 Maybe a
。