Not sure why this template is protected

Studying Haskell, and I'm not sure why I am not getting the expected result, given these definitions:

instance Ring Integer where addId = 0 addInv = negate mulId = 1 add = (+) mul = (*) class Ring a where addId :: a -- additive identity addInv :: a -> a -- additive inverse mulId :: a -- multiplicative identity add :: a -> a -> a -- addition mul :: a -> a -> a -- multiplication 

I wrote this function

 squashMul :: (Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul xy | (Lit mulId) <- x = y | (Lit mulId) <- y = x squashMul xy = Mul xy 

However:

 *HW05> squashMul (Lit 5) (Lit 1) Lit 1 

If I write one version specifically for Integer:

 squashMulInt :: RingExpr Integer -> RingExpr Integer -> RingExpr Integer squashMulInt xy | (Lit 1) <- x = y | (Lit 1) <- y = x squashMulInt xy = Mul xy 

Then I get the expected result.

Why (Lit mulId) <- x match even when x is not (Lit 1)?

+5
source share
1 answer

The variables used in pattern matching are considered local variables. Consider this definition to calculate the length of a list:

 len (x:xs) = 1 + len xs len _ = 0 

The variables x and xs are local variables for this definition. In particular, if we add a definition for a top-level variable, as in

 x = 10 len (x:xs) = 1 + len xs len _ = 0 

this does not affect the value for len . In more detail, the first pattern (x:xs) not equivalent (10:xs) . If this were interpreted in this way, we would now have len [5,6] == 0 , violating the previous code! Fortunately, the pattern matching semantics are resistant to new ads like x=10 .

Your code

 squashMul :: (Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul xy | (Lit mulId) <- x = y | (Lit mulId) <- y = x squashMul xy = Mul xy 

really mean

 squashMul :: (Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul xy | (Lit w) <- x = y | (Lit w) <- y = x squashMul xy = Mul xy 

which is wrong, since w can be arbitrary. You probably want:

 squashMul :: (Eq a, Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul xy | (Lit w) <- x , w == mulId = y | (Lit w) <- y , w == mulId = x squashMul xy = Mul xy 

(The Eq a constraint may depend on a RingExpr definition that has not been published)

You can also simplify everything:

 squashMul :: (Eq a, Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul x@ (Lit w) y | w == mulId = y squashMul x y@ (Lit w) | w == mulId = x squashMul xy = Mul xy 

or even:

 squashMul :: (Eq a, Ring a) => RingExpr a -> RingExpr a -> RingExpr a squashMul (Lit w) y | w == mulId = y squashMul x (Lit w) | w == mulId = x squashMul xy = Mul xy 

In this version, template protections are not even used, since there is no need.

+9
source

Source: https://habr.com/ru/post/1209260/


All Articles