patriques
patriques

Reputation: 5201

How does ghc perform type inference in

I working through the Paul Hudaks highly recommended book Haskell School of Expression. In the 13:th chapter I stumbled across this definition

type Time = Float

newtype Behavior a = Beh (Time -> a)

The author has declared several instances of the newtype Behavior: Eq, Show, Num, Fractional and Floating, but among these it´s only one function in one of these instance declarations that is bugging me:

instance Num a => Num (Behavior a) where
  (+) = lift2 (+)                                   -- This one!
  fromInteger = lift0 . fromInteger

lift0 :: a -> Behavior a
lift0 x = Beh (\t -> x)

lift2 :: (a -> b -> c) -> (Behavior a -> Behavior b -> Behavior c)
lift2 g (Beh a) (Beh b)
   = Beh (\t -> g (a t) (b t))                      -- Or actually this one.

time :: Behavior Time
time = Beh (\t -> t)

The author describes, after this, that with these new function declarations we can now write time + 5 and thus lift the (+) operator into the realm of Behavior, or something in that fashion. That sounds all good to me, so I nod and smile as I read along. Suddenly, the author explains that: (time + 5) is equivalent to Beh (\t -> t + 5), which sounds totally whacked. He actually even provides this unfolding of the expressions to prove it:

time + 5
==> { unfold overloadings for time, (+), and 5 }
(lift2 (+)) (Beh (\t -> t)) (Beh (\t -> 5))
==> { unfold lift2 }
(\ (Beh a) (Beh b) -> Beh (\t -> a t + b t)) (Beh (\t -> t)) (Beh (\t -> 5))
==> { unfold anonymous function }
Beh (\t -> (\t -> t) t + (\t -> 5) t )
==> { unfold two anonymous functions }
Beh (\t -> t + 5)

This is more specifically what I´m having trouble understanding. To me the correct statement would be: time + (Beh 5) is equivalent to Beh (\t -> t + 5). But when I infer the type in ghci it tells me (of course) that the author is right and that I´m stupid in some formal way. Can someone please explain it to me.

Upvotes: 3

Views: 106

Answers (1)

tempestadept
tempestadept

Reputation: 835

(+) has type Num a => a -> a -> a. Here a is Behavior Float. The literal 5 in your code is converted to Behavior Float with fromInteger, which should look like fromInteger n = Beh (\t -> fromInteger n).

Beh 5 wouldn't typecheck since Beh wraps a function of type Float -> a, not a number.

Upvotes: 5

Related Questions