2014-12-16 2 views
5

학습 하스켈 일치 왜 나는이 정의를 주어, 내가 예상 결과를 얻을하지 않는 이유 확실하지 않다 :확실하지 않음이 패턴 가드

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 
내가

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

그러나이 기능을 쓴

:

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

나는 정수에 대해 하나 개의 버전 구체적으로 작성하는 경우 :

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

그런 다음 예상되는 결과가 나옵니다.

x가 (켜짐 1)이 아니더라도 (Lit mulId) <- x이 일치하는 이유는 무엇입니까?

+5

'mulId'는 이전에 정의 된 것과 관계없는 새로운 지역 변수입니다. 대신'Lit w <- x, w == mulId = ... '를 원한다. – chi

답변

9

패턴 일치에 사용되는 변수는 지역 변수로 간주됩니다.

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

변수 xxs이 정의 로컬 변수 :리스트의 길이를 계산하기 위해이 정의를 생각 해보자. 우리가

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

같이 최상위 변수의 정의를 추가하는 경우 특히,이 len의 의미에 영향을 미치지 않습니다. 보다 상세하게는, 제 1 패턴 (x:xs)이 아니고이 아니고, (10:xs)과 동등하다. 그렇게 해석되면, 우리는 이전 코드를 깨기 위해 len [5,6] == 0이 될 것입니다! 다행히도 패턴 일치의 의미는 x=10과 같은 새 선언에 대해 강력합니다. w 임의 수 있기 때문에

코드는

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

실제로 잘못

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

을 의미한다. 당신이 원하는 것은 아마도 :

squashMul :: (Eq a, Ring a) => RingExpr a -> RingExpr a -> RingExpr a 
squashMul [email protected](Lit w) y   | w == mulId = y 
squashMul x   [email protected](Lit w) | w == mulId = x 
squashMul x   y      = Mul x y 

또는 :

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

또한 모든 것을 단순화 할 수

합니다 (Eq a 제약이 게시되지 않았습니다 RingExpr의 정의에 따라 달라질 수 있습니다) 수신자 :

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 x  y     = Mul x y 

이 버전은 필요가 없으므로 패턴 가드를 사용하십시오.

+0

감사! 마지막 메모에서 "단순화 할 수 있습니다"- 어떤면에서 더 간단합니까? 패턴 가드를 사용하지 않는다는 것만 제외하면? 가능하다면 패턴 가드를 피하는 것이 더 관례일까요? –

+0

@ j-a 패턴 가드는 Haskell의 GHC 확장 기능으로, 예를 들어 쓰기가 필요할 때 유용합니다. 'f x y | 단지 z <- g (x + y) = ...'오른쪽에는 복잡한 표현이 있습니다. 대신에'pattern <- x '를 사용할 때, 표준'x @ pattern' 구조만으로도 충분합니다. 후자는 또한 더 관용적이다. 실제로 더 단순한 것은 물론 맛의 문제입니다. – chi

+0

thx, 왜 x @ ..를 사용했는지에 대한 특별한 이유가 있습니까? squashMul x @ (Lit w) y | w == mulId = y => squashMul (Lit w) y | w == mulId = y –