Ivan Uemlianin
Ivan Uemlianin

Reputation: 1037

Haskell partial application doesn't seem to work with on. Why?

Partially applying on with a single other function seems to change the types involved.

Starting with on compare length "aaa" "bb" and peeling off items from the right, things start off predictable:

Prelude Data.Function> :t on compare length "aaa" "bb"
on compare length "aaa" "bb" :: Ordering

Prelude Data.Function> on compare length "aaa" "bb"
GT


Prelude Data.Function> :t on compare length "aaa"
on compare length "aaa" :: [Char] -> Ordering

Prelude Data.Function> let ocla = on compare length "aaa"

Prelude Data.Function> :t ocla
ocla :: [Char] -> Ordering

Prelude Data.Function> ocla "aa"
GT


Prelude Data.Function> :t on compare length
on compare length :: [a] -> [a] -> Ordering

Prelude Data.Function> let ocl = on compare length

Prelude Data.Function> :t ocl
ocl :: [a] -> [a] -> Ordering

Prelude Data.Function> ocl "aaa" "aa"
GT

But with on compare I got a surprise:

Prelude Data.Function> :t on compare
on compare :: Ord b => (a -> b) -> a -> a -> Ordering

Prelude Data.Function> let oc = on compare

Prelude Data.Function> :t oc
oc :: (a -> ()) -> a -> a -> Ordering

Prelude Data.Function> oc length "aaa" "aa"

<interactive>:27:4:
    Couldn't match type `Int' with `()'
    Expected type: [Char] -> ()
      Actual type: [Char] -> Int
    In the first argument of `oc', namely `length'
    In the expression: oc length "aaa" "aa"
    In an equation for `it': it = oc length "aaa" "aa"

Why is the type of oc not the same as the type of on compare?

Upvotes: 1

Views: 179

Answers (1)

bheklilr
bheklilr

Reputation: 54068

This is because of the dreaded Monomorphism restriction. GHCi uses the Monomorphism restriction to guess the simplest possible type for a function or value defined in interactive mode. This is usually very useful, but quite often it is dumb and picks () where you really want a typeclass restrained type, like Ord a => a. Just provide your oc function a type signature and you'll be fine:

let oc :: Ord b => (a -> b) -> a -> a -> Ordering; oc = on compare

You can turn off the Monomorphism restriction if you'd like with :set -XNoMonomorphismRestriction (thanks @Xeo), but I would recommend against it. Either put your functions in a file and load them into GHCi, or add type signatures in interactive mode.


The wiki article at http://www.haskell.org/haskellwiki/Monomorphism_restriction explains this problem in more detail.

Upvotes: 4

Related Questions