For Programmers: Free Programming Magazines  


Home > Archive > Functional > May 2007 > Non-general inference in ghc









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Non-general inference in ghc
fuhsjr00@gmail.com

2007-05-17, 7:07 pm

Hello group,

Can anyone explain to me why ghc would infer the type of

row_add {- row1 row2 -} = zipWith (+)

as

row_add :: [Integer] -> [Integer] -> [Integer]

while the type of

row_add row1 row2 = zipWith (+) row1 row2

is inferred to be

row_add :: Num a => [a] -> [a] -> [a]

?

Another oddity I've run into is that ghc inferred the second type with
the first definition when row_add was both defined and used in the
same file.

I'm fairly new to using ghc and Haskell, so if responses could be
dumbed down a bit, that would be helpful.

Thanks

Josh

Frederic Beal

2007-05-17, 10:06 pm

On 2007-05-17, fuhsjr00@gmail.com <fuhsjr00@gmail.com> wrote:
> Hello group,
>
> Can anyone explain to me why ghc would infer the type of
>
> row_add {- row1 row2 -} = zipWith (+)
>
> as
>
> row_add :: [Integer] -> [Integer] -> [Integer]
>
> while the type of
>
> row_add row1 row2 = zipWith (+) row1 row2
>
> is inferred to be
>
> row_add :: Num a => [a] -> [a] -> [a]
>
> ?


I have no answer to your question, but I can propose the following
workaroundÂ_: declare the type of your function too.

--- file foo.hs
row_add = zipWith (+)

row_add' :: Num a => [a] -> [a] -> [a]
row_add' = zipWith (+)

--- ghci toplevel
Prelude> :l foo
[1 of 1] Compiling Main ( foo.hs interpreted )
Ok, module loaded: Main.
*Main> :t row_add
row_add :: [Integer] -> [Integer] -> [Integer]
*Main> :t row_add'
row_add' :: (Num a) => [a] -> [a] -> [a]

--
Frederic
Phil Armstrong

2007-05-18, 4:19 am

Frederic Beal <frederic@nospam.yt.cs.titech.ac.jp> wrote:
> On 2007-05-17, fuhsjr00@gmail.com <fuhsjr00@gmail.com> wrote:
>
> I have no answer to your question, but I can propose the following
> workaroundÂ_: declare the type of your function too.


It's the monomorphism restriction.

See section 12.3 in http://www.haskell.org/tutorial/pitfalls.html

Phil

--
http://www.kantaka.co.uk/ .oOo. public key: http://www.kantaka.co.uk/gpg.txt
fuhsjr00@gmail.com

2007-05-19, 4:09 am

On May 18, 3:25 am, Phil Armstrong <phil-n...@kantaka.co.uk> wrote:

> See section 12.3 inhttp://www.haskell.org/tutorial/pitfalls.html


Thanks much. I read over the linked page and some sub-links, and even
though I don't fully understand the issue, it seems that I need to do
one of three things to ensure that it doesn't bite me again:

1) Define every function with its entire parameter list.
2) Declare the type of functions that return functions.
3) Define and use functions in the same module.


Josh

Ben Rudiak-Gould

2007-05-19, 10:05 pm

fuhsjr00@gmail.com wrote:
> Thanks much. I read over the linked page and some sub-links, and even
> though I don't fully understand the issue, it seems that I need to do
> one of three things to ensure that it doesn't bite me again:
>
> 1) Define every function with its entire parameter list.
> 2) Declare the type of functions that return functions.
> 3) Define and use functions in the same module.


Mm, not quite. The monomorphism restriction says that every binding that
behaves like a function must look like a function. "Behaves like a function"
here means that it gets recomputed every time it appears in the program.
"Looks like a function" means that it's bound function-style, with at least
one parameter, or that it has an appropriate type signature.

Note that the monomorphism restriction is misnamed. It's really about
*overloading*, not polymorphism. It will never apply to something that
doesn't have a type class context like (Num a). In all other cases you can
ignore it. So all three of your ideas do too much in that they apply to all
functions, not just overloaded ones. All three of your ideas do too little
in that they fail to apply to overloaded non-functions, like (minBound ::
(Num a) => a), which are also subject to the restriction. Your first idea
does too much by requiring the entire parameter list (one parameter is
enough), and your second one does too little because it fails to account for
functions which don't return functions like (negate :: (Num a) => a -> a),
and your third one does too much and too little. Module boundaries are not
really relevant, except that most compilers don't know how exported symbols
will be used and therefore have to assume the worst.

My advice is to ignore the restriction until it bites you (which probably
won't be very often), and then add type signatures to work around it. But
before you override it, you might want to check that you haven't
accidentally written very inefficient code, since that's what the
restriction is there to prevent.

-- Ben
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com