
I'm new to Haskell and functional programming; have been exploring the fixed-point combinator based on the exercise in the HSOE book. Having an odd issue with typing in ghci which I don't understand - maybe it's to do with section 3.4.5. "Type defaulting in GHCi" but I don't really grok that yet... (BTW, an unrelated question: is there a good reference where I can understand the precendence/associativity rules for Haskell? I continually find myself needing lots of parens before expressions behave as I expect, and get very confused trying to use the $ operator - usually resorting to lots of parens again :-) My typing question might boil down to this simple example, though my original example follows: -- Why don't these (particularly g and g') all have the same type? Prelude> :t (\x -> x+1) (\x -> x+1) :: (Num a) => a -> a Prelude> let g = (\x -> x+1) Prelude> :t g g :: Integer -> Integer Prelude> let g' x = x + 1 Prelude> :t g' g' :: (Num a) => a -> a -- Here's my original fixed-point combinator example: Prelude> let fix f = f (fix f) -- here's a silly (but working) implementation of length using fix: Prelude> fix (\g xs -> if xs == [] then 0 else (1 + g (tail xs))) [1,2,3,4] 4 -- so I examine the types of the parts, which seems fine: Prelude> :t fix (\g xs -> if xs == [] then 0 else (1 + g (tail xs))) ... :: (Num t, Eq a) => [a] -> t Prelude> :t (\g xs -> if xs == [] then 0 else (1 + g (tail xs))) ... :: (Num t, Eq a) => ([a] -> t) -> [a] -> t -- but now I try to bind the anonymous function to a name -- this seems to get the types wrong and no longer works as I expect: Prelude> let lenstep = (\g xs -> if xs == [] then 0 else (1 + g (tail xs))) Prelude> :t lenstep lenstep :: ([()] -> Integer) -> [()] -> Integer Prelude> :t fix lenstep fix lenstep :: [()] -> Integer Prelude> let len' = fix (\g xs -> if xs == [] then 0 else (1 + g (tail xs))) Prelude> :t len' len' :: [()] -> Integer Prelude> Prelude> len' [1,2,3,4] <interactive>:1:12: No instance for (Num ()) arising from the literal `4' at <interactive>:1:12 Possible fix: add an instance declaration for (Num ()) In the expression: 4 In the first argument of `len'', namely `[1, 2, 3, 4]' In the expression: len' [1, 2, 3, 4] -- maybe this is just me not understanding name binding properly; it seems to work if I do it this way: Prelude> let lenstep' g xs = (if xs == [] then 0 else (1 + g (tail xs))) Prelude> :t lenstep' lenstep' :: (Eq a, Num t) => ([a] -> t) -> [a] -> t Prelude> :t fix lenstep' fix lenstep' :: (Eq a, Num t) => [a] -> t Prelude> fix lenstep' [1,2,3,4] 4 -- but what's the difference? Cheers, Patrick Patrick.Surry@portraitsoftware.com mailto:Patrick.Surry@portraitsoftware.com , VP Technology Tel: (617) 457 5230 Mob: (857) 919 1700 Fax: (617) 457 5299 Map <http://maps.google.com/maps?f=q&hl=en&q=125+Summer+St,+Boston,+MA+02110 &ie=UTF8&z=15&ll=42.353153,-71.057296&spn=0.022644,0.054245&om=1&iwloc=A
Portrait Software introduces Portrait Campaign Manager http://www.portraitsoftware.com/Products/portrait_campaign_manager : Easy, integrated campaign management for automated and highly targeted outbound marketing http://supportcentre.portraitsoftware.com/Vmail/emailfooter/balloon.gif http://www.portraitsoftware.com/ http://supportcentre.portraitsoftware.com/Vmail/emailfooter/portrait_sof tware_logo.gif http://www.portraitsoftware.com/ www.portraitsoftware.com http://www.portraitsoftware.com/ ________________________________________________________________________ DISCLAIMER: This e-mail is intended only for the addressee named above. As this e-mail may contain confidential or privileged information, if you are not the named addressee, you are not authorised to retain, read, copy or disseminate this message or any part of it. If you received this email in error, please notify the sender and delete the message from your computer.

On Wed, Apr 02, 2008 at 04:26:04PM -0400, Patrick Surry wrote:
-- Why don't these (particularly g and g') all have the same type? Prelude> :t (\x -> x+1) (\x -> x+1) :: (Num a) => a -> a Prelude> let g = (\x -> x+1) Prelude> :t g g :: Integer -> Integer Prelude> let g' x = x + 1 Prelude> :t g' g' :: (Num a) => a -> a
It's the monomorphism restriction in action, along with defaulting. Basically, the rule is: Any binding of the form "g = ..." where there are no parameters *syntactically* must not be polymorphic with type-class restrictions. If you disable it with -fno-monomorphism-restriction then the differences go away. In addition, Haskell has some special-case "defaulting" rules for turning Num classed type-variables into concrete types, which explains the appearance of "Integer" specifically. The reason for existence of this restriction is that such a "g" may be recomputed for each use, much like a function call. This could lead to surprising behavior, though perfectly safe. In Haskell, it's not such a big deal, because of pure code, so some people prefer to turn the restriction off. Your options are to turn it off, always write syntactic parameters like "g x = ...", or provide an explicit polymorphic type signature like "g :: Num a => a -> a". -- -- Matthew Danish -- user: mrd domain: cmu.edu -- OpenPGP public key: C24B6010 on keyring.debian.org

Thanks for the quick reply - I'm not sure I really understand exactly what your rule means, but it's led me over to http://www.haskell.org/haskellwiki/Monomorphism_restriction where it seems possible that I might eventually figure it out :) Any thoughts on the other question about where I can go to understand Haskell's precedence/associativity rules better (and avoid so many parens)? Cheers, Patrick -----Original Message----- From: Debian User [mailto:mdanish@andrew.cmu.edu] Sent: Wednesday, April 02, 2008 4:40 PM To: Patrick Surry Cc: glasgow-haskell-users@haskell.org Subject: Re: Confused about typing in ghci On Wed, Apr 02, 2008 at 04:26:04PM -0400, Patrick Surry wrote:
-- Why don't these (particularly g and g') all have the same type? Prelude> :t (\x -> x+1) (\x -> x+1) :: (Num a) => a -> a Prelude> let g = (\x -> x+1) Prelude> :t g g :: Integer -> Integer Prelude> let g' x = x + 1 Prelude> :t g' g' :: (Num a) => a -> a
It's the monomorphism restriction in action, along with defaulting. Basically, the rule is: Any binding of the form "g = ..." where there are no parameters *syntactically* must not be polymorphic with type-class restrictions. If you disable it with -fno-monomorphism-restriction then the differences go away. In addition, Haskell has some special-case "defaulting" rules for turning Num classed type-variables into concrete types, which explains the appearance of "Integer" specifically. The reason for existence of this restriction is that such a "g" may be recomputed for each use, much like a function call. This could lead to surprising behavior, though perfectly safe. In Haskell, it's not such a big deal, because of pure code, so some people prefer to turn the restriction off. Your options are to turn it off, always write syntactic parameters like "g x = ...", or provide an explicit polymorphic type signature like "g :: Num a => a -> a". -- -- Matthew Danish -- user: mrd domain: cmu.edu -- OpenPGP public key: C24B6010 on keyring.debian.org ________________________________________________________________________ DISCLAIMER: This e-mail is intended only for the addressee named above. As this e-mail may contain confidential or privileged information, if you are not the named addressee, you are not authorised to retain, read, copy or disseminate this message or any part of it. If you received this email in error, please notify the sender and delete the message from your computer.

On Wed, Apr 02, 2008 at 04:54:36PM -0400, Patrick Surry wrote:
Thanks for the quick reply - I'm not sure I really understand exactly what your rule means, but it's led me over to http://www.haskell.org/haskellwiki/Monomorphism_restriction where it seems possible that I might eventually figure it out :)
Really, don't overthink it too much. Anything that looks like g = ... syntactically (that means, as written in the file) cannot have a polymorphic type-class restricted type (something with a "=>" in the type). The distinction being made is that "g = ..." has nothing but space in between the "g" and the "=". No parameters syntactically.
Any thoughts on the other question about where I can go to understand Haskell's precedence/associativity rules better (and avoid so many parens)?
The Haskell Report, perhaps? -- -- Matthew Danish -- user: mrd domain: cmu.edu -- OpenPGP public key: C24B6010 on keyring.debian.org
participants (2)
-
Matthew Danish
-
Patrick Surry