Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I map a function that multiplies by a Fractional onto a list of Nums?

I want to make a list of numbers every 0.1 from -150 to 150.

To do this, I created a list, and then tried to map a Fractional multiplication lambda onto it, like so:

let indices = [-1500,-1499..1500]
let grid = map (\x -> 0.1 *x) indices

This makes ghci spit out an error.

On the other hand, both of these work fine:

let a = 0.1*2

and

let grid = map (\x -> 2 *x) indices

What's going on here? Why does multiplication of a Num by a Fractional only fail when applied to a list with map?

EDIT: The error I get is:

No instance for (Fractional Integer)
  arising from the literal `0.1'
Possible fix: add an instance declaration for (Fractional Integer)
In the first argument of `(*)', namely `0.1'
In the expression: 0.1 * x
In the first argument of `map', namely `(\ x -> 0.1 * x)'
like image 396
Dan Avatar asked Apr 04 '13 05:04

Dan


2 Answers

You've discovered the "dreaded monomorphism restriction". Basically GHC will infer the type of indices to be a monotype like [Integer] instead of Num a => a. You can either provide an annotation like indices :: [Float], or rework your definitions to avoid the restriction.

For example (not a suggestion), if you make indices a function: let indices a = [-1500, -1499..1500], the inferred type is now (Enum t, Num t) => a -> [t]. The a parameter is unused but defeats the restriction. Then you can then do map f (indices whatever). See much more information in the Haskell Wiki about the Monomorphism Restriction.

like image 199
kputnam Avatar answered Oct 04 '22 23:10

kputnam


This is defaulting.

Your indices variable, rather than being polymorphic over the Num typeclass as you might expect, is defaulting to Integer, at which point you can't multiply it by 0.1, since 0.1 will resolve to some Fractional type.

You could force indices to be polymorphic with an explicit type signature:

let indices :: (Enum a, Num a) => [a]; indices = [-1500,-1499..1500]

although in practice you don't often want explicitly polymorphic lists in that way.

There is a page about the monomorphism restriction on the haskell wiki although it's not particularly succinct : http://www.haskell.org/haskellwiki/Monomorphism_restriction

like image 30
drquicksilver Avatar answered Oct 04 '22 23:10

drquicksilver