From 44644ebe79c748861894de4813efd47dae6cb945 Mon Sep 17 00:00:00 2001 From: simonpj Date: Wed, 9 Mar 2005 10:54:57 +0000 Subject: [PATCH] [project @ 2005-03-09 10:54:57 by simonpj] Add notes about implicit parameters; pls merge --- ghc/docs/users_guide/glasgow_exts.xml | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/ghc/docs/users_guide/glasgow_exts.xml b/ghc/docs/users_guide/glasgow_exts.xml index efd7a13..4836749 100644 --- a/ghc/docs/users_guide/glasgow_exts.xml +++ b/ghc/docs/users_guide/glasgow_exts.xml @@ -2108,6 +2108,68 @@ the binding for ?x, so the type of f is + +Implicit parameters and polymorphic recursion + + +Consider these two definitions: + + len1 :: [a] -> Int + len1 xs = let ?acc = 0 in len_acc1 xs + + len_acc1 [] = ?acc + len_acc1 (x:xs) = let ?acc = ?acc + (1::Int) in len_acc1 xs + + ------------ + + len2 :: [a] -> Int + len2 xs = let ?acc = 0 in len_acc2 xs + + len_acc2 :: (?acc :: Int) => [a] -> Int + len_acc2 [] = ?acc + len_acc2 (x:xs) = let ?acc = ?acc + (1::Int) in len_acc2 xs + +The only difference between the two groups is that in the second group +len_acc is given a type signature. +In the former case, len_acc1 is monomorphic in its own +right-hand side, so the implicit parameter ?acc is not +passed to the recursive call. In the latter case, because len_acc2 +has a type signature, the recursive call is made to the +polymoprhic version, which takes ?acc +as an implicit parameter. So we get the following results in GHCi: + + Prog> len1 "hello" + 0 + Prog> len2 "hello" + 5 + +Adding a type signature dramatically changes the result! This is a rather +counter-intuitive phenomenon, worth watching out for. + + + +Implicit parameters and monomorphism + +GHC applies the dreaded Monomorphism Restriction (section 4.5.5 of the +Haskell Report) to implicit parameters. For example, consider: + + f :: Int -> Int + f v = let ?x = 0 in + let y = ?x + v in + let ?x = 5 in + y + +Since the binding for y falls under the Monomorphism +Restriction it is not generalised, so the type of y is +simply Int, not (?x::Int) => Int. +Hence, (f 9) returns result 9. +If you add a type signature for y, then y +will get type (?x::Int) => Int, so the occurrence of +y in the body of the let will see the +inner binding of ?x, so (f 9) will return +14. + + -- 1.7.10.4