i'm new haskell , come across puzzling example me in haskell programming first principles book. @ end of chapter 6 occurred me following doesn't work:
constant :: (num a) => constant = 1.0
however, following works fine:
f :: (num a) => -> f x = 3*x
i can input numerical value x
function f
, nothing break. it's not constrained taking integers. makes sense me intuitively. example constant totally confusing me.
over on reddit thread book explained (paraphrasing) reason why constant example doesn't work type declaration forces value of constant
things aren't more specific num
. trying assign value subclass of num
fractional
isn't kosher.
if explanation correct, wrong in thinking these 2 examples seem opposites of each other? in 1 case, type declaration forces value general possible. in other case, accepted values function can anything implements num
.
can set me straight on this?
it can read types game played between 2 actors, implementor of type , user of type. job of explaining perspective, have introduce haskell hides default: add binders type variables. types become:
constant :: forall a. num => f :: forall a. num => ->
now, read type formation rules thusly:
forall a. t
means: caller chooses typea
, , game continuest
c => t
means: caller shows constraintc
holds, , game continuest
t -> t'
means: caller chooses value of typet
, , game continuest'
t
(wheret
monomorphic type such bare variable orinteger
or similar) means: implementor produces value of typea
we need few other details understand things here, them here:
- when write number no decimal points, compiler implicitly converts call
frominteger
appliedinteger
produced parsing number. havefrominteger :: forall a. num => integer -> a
. - when write number decimal points, compiler implicitly converts call
fromrational
appliedrational
produced parsing number. havefromrational :: forall a. fractional => rational -> a
. - the
num
class includes method(*) :: forall a. num => -> -> a
.
now let's try walk through 2 examples , carefully.
constant :: forall a. num => constant = 1.0 {- = fromrational (1 % 1) -}
the type of constant
says: caller chooses type, shows type implements num
, , implementor must produce value of type. implementor tries play own game calling fromrational :: fractional => rational -> a
. chooses same type caller did, , makes attempt show type implements fractional
. oops! can't show that, because thing caller proved him a
implements num
-- doesn't guarantee a
implements fractional
. dang. implementor of constant
isn't allowed call fromrational
@ type.
now, let's @ f
:
f :: forall a. num => -> f x = 3*x {- = frominteger 3 * x -}
the type of f
says: caller chooses type, shows type implements num
, , chooses value of type. implementor must produce value of type. going playing own game (*)
, frominteger
. in particular, chooses same type caller did. frominteger
, (*)
demand prove type instance of num
-- passes off proof caller gave him of , saves day! chooses integer
3
argument frominteger
, , chooses result of , value caller handed him 2 arguments (*)
. satisfied, , implementor gets return new value.
the point of whole exposition this: num
constraint in both cases enforcing exactly same thing, namely, whatever type choose instantiate a
@ must member of num
class. it's in definition constant = 1.0
being in num
isn't enough operations we've written, whereas in f x = 3*x
being in num
is enough operations we've written. , since operations we've chosen 2 things different, should not too surprising 1 works , other doesn't!
Comments
Post a Comment