简单回答:don't! Haskell 不是面向对象语言,假装它是面向对象语言并试图将继承模式转换为类型类和 ADT 的混合体并没有多大用处。 https://stackoverflow.com/questions/20184286/object-oriented-programming-in-haskell/20188103#20188103.
Your List<Foo>
在 Java 中与Foo a => [a]
在 Haskell 中:这样的签名实际上意味着forall a . Foo a => [a]
. The a
基本上是函数的额外参数,即它可以从外部选择特定的Foo
这里使用的是实例。
Quite the opposite in Java: there you don't have any control of what types are in the list at all, only know that they implement the Foo
interface. In Haskell, we call this an existential type, and generally avoid it because it's stupid. Ok, you disagree – sorry, you're wrong!
...No, seriously, if you have such an existential list, the only thing you can ever do1 is execute the bar
action. Well, then why not simply put that action in the list right away! IO()
actions are values just like anything else (they aren't functions; anyway those can be put in lists just as well). I'd write your program
xs :: [IO ()]
xs = [bar Bar1, bar Bar2]
That said, if you absolutely insist you can have existential lists in Haskell as well:
{-# LANGUAGE ExistentialQuantification #-}
data AFoo = forall a. Foo a => AFoo a
xs :: [AFoo]
xs = [AFoo Bar1, AFoo Bar2]
main = mapM_ (\(AFoo f) -> bar f) xs
因为这已经成为一种咆哮:我确实承认 OO 风格对于某些应用程序来说比 Haskell 的函数式风格更方便。存在确实有其有效的用例(不过,像 chunksOf 50 一样,我更喜欢将它们写为GADTs http://www.haskell.org/haskellwiki/GADTs_for_dummies)。只是,对于很多问题,Haskell 允许提供更简洁、更强大、更通用的解决方案,但在许多方面比您在 OO 编程中使用的“如果您只有一把锤子……”继承更简单,因此在使用存在性之前,您需要应该对 Haskell 的“原生”功能有一个正确的感觉。
1Yeah, I know you can also do "typesafe dynamic casts" etc. in Java. In Haskell, there's the Typeable
class for this kind of stuff. But you might as well use a dynamic language right away if you take such paths.