[Haskell-beginners] Question on Real World Haskell ch.13 SymbolicManip

Jake Penton djp at arqux.com
Wed Jun 1 04:37:22 CEST 2011


On 2011-05-31, at 9:20 PM, Mike Meyer wrote:

> On Tue, 31 May 2011 20:48:41 -0400
> Jake Penton <djp at arqux.com> wrote:
> 
>> Greetings. I post here from time to time as I work my way through Real World Haskell. I believe that I have understood most of what I have studied. However, today I ran into something that seems like magic.
>> 
>> I hope it's ok to refer to RWH here, as I believe that the book is very commonly used for learning the language. I'll include the code that is puzzling me here anyway, though.
>> 
>> On p.310 of RWH we have:
>> 
>> data Op = Plus | Minus | Mul | Div | Pow
>>        deriving (Eq, Show)
>> 
>> data SymbolicManip a = 
>>    Number a
>>  | Arith Op (SymbolicManip a) (SymbolicManip a)
>>    deriving (Eq, Show)
>> 
>> instance Num a => Num (SymbolicManip a) where
>>    a + b = Arith Plus a b
>>    a - b = Arith Minus a b
>>    a * b = Arith Mul a b
>>    negate a = Arith Mul (Number (-1)) a
>>    abs a = error "abs is unimplemented"
>>    signum _ = error "signum is unimplemented"
>>    fromInteger i = Number (fromInteger i)
>> 
>> Ok, so far so good. But the following example seems quite astounding to me:
>> 
>> ghci> (5 * 10 + 2)::SymbolicManip Int
>> Arith Plus (Arith Mul (Number 5) (Number 10)) (Number 2)
>> 
>> The book says to notice that haskell "converted" 5 * 10 + 2 into a SymbolicManip. Indeed!
>> 
>> My understanding breaks down at this point. I suspect that it may be my weak grasp of the implications of lazy evaluation, and typeclasses generally. My (incorrect) intuition makes me think that the stuff inside the parentheses should be evaluated first, and then typed as a SymbolicManip. This would give the result Number 52. 
>> 
>> My question may be too vague to answer easily, but what I am hoping for is a bit of a narrative regarding how haskell knows that the pieces inside the parentheses are each of type SymbolicManip Int. Or something like that....
> 
> 
> I'm working through the book as well (at least, when I'm not otherwise
> occupied), so will take a stab at an answer to see if *I* understand
> it properly.
> 
> This doesn't have anything to do with lazy evaluation, but with type
> inferencing. The type of the entire expression is "SymbolicManip Int"
> (SMI from now on) because - well, you said it is. Since the type of
> the expression is SMI, the type of (X + 2) must be SMI, which means
> the (+) function has to produce that result type, and the only
> function that does that is the SMI instance of Num. Since it's two
> arguments are of type SMI, the sub-expression (5 * 10) gets the same
> treatment, and then all of the integers gets turned into an SMI using
> the function specified by fromInteger because they also have to be of
> type SMI.
> 

Ok, thanks - very helpful to me. I think (maybe) I see why I thought lazy evaluation was involved, although I may still be reasoning badly.

I was perhaps reverting to C thinking, treating the type SymbolicManip Int as a type-cast rather than as a type, and assuming that it would be possible to evaluate (5 * 10 + 2)  first (whatever the heck that might mean) and then convert it. I somehow imagined that evaluating the expression lazily might do something good - heaven knows what - in this respect.

My understanding now is that type inference is necessary (to arrive at an instance of Num) in order for (+) and (*) to have meaning, My notion of evaluating the expression before type inference is probably just silly, in that light.

I think I also see why the implicit wrapping of integer literals in fromInteger is essential. This is mentioned in RWH, and also by Brandon Allbery's response to my post, but I did not grasp it initially.

Thanks again.

Best, 

- Jake -
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20110531/c6f27623/attachment-0001.htm>


More information about the Beginners mailing list