我正在尝试克服多年在经典Java风格的继承模型中工作,以真正适应Haskell . 它进展不顺利,我需要一些帮助 .
假设我有一个类型类 Foo
. 我想表示 Foo
的任意实现类的列表,但不是以限制列表中的每个项目相同的方式;我需要一个异构的开放类型,所以我的库的消费者可以实现自己的 Foo
.
原因是因为我想写下面的内容(pidgin Haskell):
class Foo -- something...
data Bar = Bar Int Char
data Baz = Baz String
instance Foo Bar
instance Foo Baz
saySomething :: Foo -> String
saySomething (Bar x _) = "Bar number " ++ (show x)
saySomething (Baz x) = "Your baz is " ++ x
saySomething _ = "Unknown Foo"
sayAll :: [Foo] -> [String]
sayAll = map (saySomething)
main = putStrLn $ sayAll [ (Bar 5 'k'), (Bar 7 'G'), (Baz "hello") ]
How would I create an extensible typeclass (or other datatype) that can be freely mixed with others of the same typeclass, but not necessarily the same exact type?
2 回答
你在找什么Heterogenous collections
恕我直言,最好的方法是使用存在,如维基上所述:
你正在尝试做什么(异类)收集的问题是:一旦你有
Foo
的列表,很难回到原始类型 . 但是,如果您乐于忘记原始类型,另一种解决问题的方法是将数据转换为Foo
. 这种方法可能看似错误,但请记住,数据在Haskell中是不可变的,所以你永远无法修改你的对象,所以你可以用你的Foo
来获取信息 . 然后,像Foo
这样的真实Bar
和作为Bar
版本的新Foo
之间没有区别(同样,Haskell懒惰,所以转换将仅在需要时进行) .当你意识到这一点,你甚至可以更进一步,取而代之的是
object
,但只是一堆功能(如@chi链接中所述) . 你的代码变成了请注意,即使
somethingElse
不是一个普通函数,它也永远不会被调用(在本例中) .toFoo
的结果可以看作是Bar
和Foo
之间的桥梁 .