如何将以下 Java 实现转换为 Haskell?

这里的主要目的是拥有一个包含各种元素的列表,这些元素是特定界面的子类型。
我试图在下面制作一个 Haskell 版本,但未能达到我的目的。
这里的重点是xs有类型 [Bar]而不是 Foo a => [a]
这是否意味着 Haskell 不能做到这一点,我应该换一种方式思考吗?

java

interface Foo { 
    void bar (); 
} 
 
public class Bar1 implements Foo { 
    @Override 
    public void bar() { 
        System.out.println("I am bar 1 class"); 
    }    
} 
 
public class Bar2 implements Foo { 
    @Override 
    public void bar() { 
        System.out.println("I am bar 2 class"); 
    }    
} 
 
public static void main(String[] args) { 
    // The major purpose here is having a list  
    // that contains elements which are sub-type of "Foo" 
    List<Foo> ys = new ArrayList<Foo>(); 
 
    Foo e1 = new Bar1(); 
    Foo e2 = new Bar2(); 
 
    ys.add(e1); 
    ys.add(e2); 
 
    for (Foo foo : ys) { 
        foo.bar(); 
    } 
} 

haskell
class Foo a where 
  bar :: a -> IO () 
 
data Bar = Bar1 | Bar2 
 
instance Foo Bar where 
  bar Bar1 = print "I am Bar1" 
  bar Bar2 = print "I am Bar2" 
 
--xs :: Foo a => [a] 
xs :: [Bar] 
xs = [Bar1, Bar2] 
 
main :: IO () 
main = mapM_ bar xs 

请您参考如下方法:

简单回答:don't! Haskell is not an OO language, and it's not much good pretending it is and just trying to translate inheritance patterns to a mixture of type classes and ADTs .

您的 List<Foo>在 Java 中与 Foo a => [a] 完全不同。在 Haskell 中:这样的签名实际上意味着 forall a . Foo a => [a] . a基本上是函数的一个额外参数,即可以从外部选择特定的 Foo此处使用实例。

在 Java 中恰恰相反:你根本无法控制列表中的类型,只知道它们实现了 Foo界面。在 Haskell 中,我们称其为存在类型,并且通常避免使用它,因为它很愚蠢。好吧,你不同意——对不起,你错了!
...不,说真的,如果你有这样一个存在列表,你唯一能做的就是执行 bar行动。好吧,那为什么不立即将该操作放入列表中! IO() Action 和其他任何东西一样都是值(它们不是函数;无论如何,它们也可以放在列表中)。我会写你的程序

xs :: [IO ()] 
xs = [bar Bar1, bar Bar2] 

也就是说,如果你绝对坚持你也可以在 Haskell 中拥有存在列表:
{-# 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 )。只是,对于许多问题,Haskell 允许更简洁、强大、通用,但在许多方面比在 OO 编程中使用的“如果你只有一把锤子......”继承更简单的解决方案,所以在使用存在之前你应该对 Haskell 的“原生”特性有一个正确的感觉。

1是的,我知道您还可以在 Java 中执行“类型安全动态转换”等。在 Haskell 中,有 Typeable这类东西的课。但是,如果您采用这样的路径,您不妨立即使用动态语言。


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!