Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make an heterogeneous list in Haskell? (originally in Java)

How to convert following Java implementation into Haskell?

The major purpose here is having a list that contains various elements which are sub-type of a particular interface.
I tried to make a Haskell version below but fail to meet my purpose. The point here is xs has type [Bar] rather than Foo a => [a]

Do that mean Haskell can not do this and shall I think in another way?

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
like image 958
Simon Avatar asked Jan 08 '14 13:01

Simon


People also ask

How do u create a heterogeneous list in Java?

List<Integer> startnodes = ImmutableList. of(397251,519504,539122,539123,539124,539125); List<Integer> endnodes = ImmutableList. of(539126,539127,539142,539143,539144,539145); List<String> rp = ImmutableList.

Can lists in Haskell have different types?

One is of type (String,Int) , whereas the other is (Int,String) . This has implications for building up lists of tuples. We could very well have lists like [("a",1),("b",9),("c",9)] , but Haskell cannot have a list like [("a",1),(2,"b"),(9,"c")] . Which of these are valid Haskell, and why?

Are Haskell lists homogeneous?

Lists in Haskell must be type-homogeneous.


1 Answers

Simple answer: 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.

Your List<Foo> in Java is quite substantially different from a Foo a => [a] in Haskell: such a signature actually means forall a . Foo a => [a]. The a is basically an extra argument to the function, i.e. it can be chosen from the outside what particular Foo instance is used here.

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

As this has become quite a rant: I do acknoledge that OO style is for some applications more convenient than Haskell's functional style. And existentials do have their valid use cases (though, like chunksOf 50, I rather prefer to write them as GADTs). Only, for lots of problems Haskell allows for far more concise, powerful, general, yet in many ways simpler solutions than the "if all you have's a hammer..." inheritance you'd use in OO programming, so before using existentials you should get a proper feeling for Haskell's "native" features.


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.

like image 124
leftaroundabout Avatar answered Jan 03 '23 22:01

leftaroundabout