[Haskell-beginners] why isnt this optimized?

Guillaume Bouchard guillaum.bouchard+haskell at gmail.com
Fri Sep 16 08:54:05 UTC 2016


Hello,

Observe this example :

Prelude> let x = f 30 in (x,x)
(832040,832040)
(3.70 secs, 1,649,318,104 bytes)

Prelude> let x = (f 30) :: Int in (x,x)
(832040,832040)
(1.77 secs, 854,498,640 bytes)

If we force the result type of f 30 to Int, the result is shared as expected.

This is related to the monomorphism restriction
https://wiki.haskell.org/Monomorphism_restriction

We can observe the type of (x, x) :

Prelude> let y = (let x = f 30 in (x, x))
Prelude> :t y
y :: (Num t1, Num t) => (t, t1)


Both value does not have the same type. Actually `f` is a polymorphic
function which can compute the result for any type t as long as t is a
`Num`. So we can compute it for `Double`, `Float`,
`BigMatriceOf100GigaBytesOfInfinitePrecisionRationalNumbers`. The
compiler will only know the final type when needed, later. Actually,
the (x, x) tuple is already computed (but `x` are unevaluated) when,
by displaying it, you decide to fix `x` as `Integer` for both (the
default `Num`).

The setting is a bit different for compiled code, because in this
case, the compiler choose the type earlier. For example, in a file
`Foo.hs`

a = 10
y = (a, a) :: (Float, Integer)


BlorkBlork.hs:2:9: error:
    • Couldn't match expected type ‘Integer’ with actual type ‘Float’
    • In the expression: a
      In the expression: (a, a) :: (Float, Integer)
      In an equation for ‘z’: z = (a, a) :: (Float, Integer)
Failed, modules loaded: none.

Because the compiler takes the first encountered type (Float) as the type of a.

However you can keep the polymorphism with a type signature :

a :: Num t => t
a = 10

y = (a, a) :: (Float, Integer)

This is one of the rare case where adding a type signature adds
polymorphism compared to the infered type.

Will works.

Hope this help.

-- 
G.

On Fri, Sep 16, 2016 at 4:24 AM, Gunnar Quehl <hasquehl at gmx.de> wrote:
> Hi,
>
> I wrote a recursive fibonacci function in ghci:
>
> :set +m
>
> let
> f 0 = 0
> f 1 = 1
> f n = f (n-1) + f (n-2)
>
> As expected calculation f 30 takes a while. About 5s on my machine.
> What I don't understand is that
>
> let x = f 30 in (x,x)
>
> takes twice as long. Why is ghci reevaluating the x twice? Isn't in always
> said,
> that it can optimize because we can replace same by same and so on.
>
> Actually if compiled the behaviour is as expected.
>
> main = print $ let x = f 34 in (x)
>
> and
>
> main = print  $ let x = f 34 in (x,x)
>
> both take about 3s.
>
> Why is this not the case in the interactive enviroment?
>
> Thanks
> Gunnar
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


More information about the Beginners mailing list