
Ask HN: Am I crazy?  Odd symmetry between Haskell and Java - AnimalMuppet
Let&#x27;s say that I have a function x that returns a Foo, a function y that takes a Foo and returns a Bar, and a function z that takes a Bar and returns a Baz.  This is perfect:  we just call z(y(x)).<p>Then we discover a corner case, or the requirements change, and now there&#x27;s a situation where x can&#x27;t return a valid Foo.  In Haskell, then, we have x return a Maybe Foo, and y take a Maybe Foo.  Then y either handles the Nothing case using a pattern, or else returns a Maybe Bar.  If y returns a Maybe Bar, then z handles the Nothing, or else returns a Maybe Baz.<p>In Java, x throws an exception.  y and z either handle the exception or also throw it.<p>In both cases, I have to change the function definition (to take and&#x2F;or return a Maybe in the case of Haskell, to declare the exception in the case of Java).  It seems like they&#x27;re doing almost exactly the same thing (except that Java is considerably more verbose).<p>So, where&#x27;s the advantage to Haskell (other than wordiness)?  I&#x27;m sure someone will say &quot;composability&quot;, but how does the Maybe compose in a way that the exception does not?
======
codygman
> Let's say that I have a function x that returns a Foo, a function y that
> takes a Foo and returns a Bar, and a function z that takes a Bar and returns
> a Baz. This is perfect: we just call z(y(x)).

update: I created an interactive tutorial[0]

Alright, here is my code (I can verify it is runnable/working on ghc 7.8):

    
    
        data Foo = Foo deriving Show
        data Bar = Bar deriving Show
        data Baz = Baz deriving Show
        
        x :: Foo
        x = Foo
        
        y :: Foo -> Bar
        y _ = Bar
        
        z :: Bar -> Baz
        z _ = Baz
    

> Then we discover a corner case, or the requirements change, and now there's
> a situation where x can't return a valid Foo. In Haskell, then, we have x
> return a Maybe Foo, and y take a Maybe Foo.

I'm only going to make one change to x:

    
    
        - x :: Foo
        - x = Foo
    
        + x :: Maybe Foo
        + x = Just Foo
    

You don't have to change caller y to take a maybe Foo for one, you can leave
it as is and use:

    
    
        λ> fmap y x
    

Let me remind you of the type of fmap:

    
    
        fmap :: Functor f => (a -> b) -> f a -> f b
    

specialized to the case of Maybe's functor instance and our types:

    
    
        fmap :: (Foo -> Bar) -> Maybe Foo -> Maybe Bar
    
    

> Then y either handles the Nothing case using a pattern, or else returns a
> Maybe Bar.

In this case you can see by the definition of fmap a Maybe Bar is returned.

> If y returns a Maybe Bar, then z handles the Nothing, or else returns a
> Maybe Baz.

Just as we don't have to change our definition of z.

Our final composed function is just:

    
    
        z . y <$> x
    

So the final code looks like this:

    
    
        import Control.Applicative (<$>) -- must import explicitly before GHC 7.10
    
        data Foo = Foo deriving Show
        data Bar = Bar deriving Show
        data Baz = Baz deriving Show
        
        x :: Maybe Foo
        x = Just Foo
        
        y :: Foo -> Bar
        y _ = Bar
        
        z :: Bar -> Baz
        z _ = Baz
        
        main = print (z . y <$> x)
    
    

It sounds like you previously thought all the functions had to be updated and
it had to look something like this:

    
    
        data Foo = Foo deriving Show
        data Bar = Bar deriving Show
        data Baz = Baz deriving Show
        
        x :: Maybe Foo
        x = Just Foo
        
        y :: Maybe Foo -> Maybe Bar
        y _ = Just Bar
        
        z :: Maybe Bar -> Maybe Baz
        z _ = Just Baz
        
        main = print (z . y $ x)
    

Does this make the composabiltity clear? Is it clear how fmap (aka <$>)
eliminated the problem having to update all of those functions whereas in a
less composable language it would be necessary?

If you are interested in more information about functor, applicative, and
monad check out Adits awesome "Functors, applicatives, and monads in pictures"
tutorial[1]. The pictures/diagrams in it helped me really make sense of
applicatives, functors, and monads.

0: [https://www.fpcomplete.com/user/codygman/real-world-fmap-
exa...](https://www.fpcomplete.com/user/codygman/real-world-fmap-example)

1:
[http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)

