Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Type Deduction work in Haskell?

I'm trying to broaden my mind by learning Haskell.

My self-inflicted homework was to build a clock-tick generator which would give me Poisson-distributed intervals, and the end result (after a long struggle, I admit) was this:

import System.Random
poissonStream :: ( Ord r, Random r, Floating r, RandomGen g) => r -> r -> r -> g -> [r]
poissonStream rate start limit gen 
        | next > limit = [] 
        | otherwise     = next:(poissonStream rate next limit newGen)
        where  (rvalue, newGen) = random gen
               next = start - log(rvalue) / rate  

But there are two things (at least) I don't understand:

Why do I need "Ord r" as well as "Floating r"? (I would have expected some kind of automatic inheritance: "Floating" implies "Ord".)

By what path is the implied type definition "rvalue :: Float" achieved? In GHCi I get what I would have expected:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100)
<interactive>:1:23:
    Ambiguous type variable `t' in the constraint:
      `Random t' arising from a use of `random' at <interactive>:1:23-43
    Probable fix: add a type signature that fixes these type variable(s)

rvalue is a loose cannon which I have to tie down:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100) :: (Float, StdGen)
*Main System.Random> rvalue
0.18520793

Please be gentle with a Haskell n00b.

like image 410
Brent.Longborough Avatar asked Aug 29 '09 15:08

Brent.Longborough


2 Answers

Why do I need "Ord r" as well as "Floating r"? (I would have expected some kind of automatic inheritance: "Floating" implies "Ord".)

Floating is supposed to classify all floating-point numbers, including complex ones. There is no ordering for complex numbers. You could use RealFloat instead of Floating, which implies Ord.

By what path is the implied type definition "rvalue :: Float" achieved?

Well you can infer that from the context in which rvalue is used. It's the argument to log, and

:t log

gives

log :: (Floating a) => a -> a

so rvalue must be in the Floating class (so it will be "some type in the Floating typeclass, not precisely Float). Further, the result of log is of the same type as its input and is used in a computation with start and rate and is compared with limit which are all of type r, so rvalue will be of r (which is suitable because r is of Floating as well).

In your GHCi example, there is no more context. Type

 :t random (mkStdGen 100)

This gives you

random (mkStdGen 100) :: (Random a) => (a, StdGen)

GHCi doesn't know what type to fill in for a here. It only knows it's got to be in typeclass Random.

like image 90
Rüdiger Hanke Avatar answered Oct 07 '22 12:10

Rüdiger Hanke


In Haskell, Ord and Floating are independent or orthogonal concepts. Perhaps you were assuming that Floating only referred to very specific types, like Double and Float (this would be the case in most other languages)?

As Rudiger pointed out, there are types that are instances of the class Floating that are not Ord because there is no ordering for certain float types, like Complex. Another example besides Complex numbers would be vectors, for which you may define these Floating functions, but not any kind of sensible Ord-ering.

Remember that type classes just specify the set of functions (like an interface in Java or C#, if that's a helpful way of thinking about it) that must be defined for a type a; to be Ord, a type a just needs comparison operators, and to be an instance of Floating, a type a just needs to implement Fractional and have the functions pi, exp, sqrt, log, sin, cos, ... defined for them. That's all Floating means, nothing more, nothing less.

like image 28
Jared Updike Avatar answered Oct 07 '22 12:10

Jared Updike