2014-12-20 2 views
2

하스켈을 사용하여 수학 표현을 쓰고 싶습니다. 예를 들어 :하스켈에서 수학 표현식을 쓰는 관용적 인 방법

foo = (3 * 'x' + 2 * 'y' -- => 3x+2y 

AddMul 사업자 + 각각 *에 의해 대체 될 수 있다는 등의 방법으로 아래에서 구현을 다시 작성하는 방법이 있나요?

data Expr = Const Integer 
      | Var Char 
      | Add Expr Expr 
      | Mul Expr Expr 
      deriving (Show) 
... 
foo = Add (Mul (Const 3) (Var 'x')) (Mul (Const 3) (Var 'y')) 

지옥처럼 추악합니다. TypeOperator를 사용하면 작동하지 않으므로 연산자 앞에 :이 있어야합니다.

infixl 4 :+: 
infixl 5 :*:, :/: 
infixr 6 :^: 

data Expr = Const Integer 
      | Var Char 
      | Expr :+: Expr 
      | Expr :*: Expr 
      | Expr :^: Expr 
      | Expr :/: Expr 
      deriving (Eq, Show) 

식의 선언이 될 것입니다 :

foo = (Const 3 :*: Var 'x') :+: (Const 2 :*: Var 'y') 

덜 추한,하지만 여전히 나쁜. 어떤 아이디어?

답변

7
{-# LANGUAGE OverloadedStrings #-} 

import Data.String 

data Expr = Const Integer 
      | Var Char 
      | Add Expr Expr 
      | Mul Expr Expr 
      deriving (Show) 

instance Num Expr where 
    (+) = Add 
    (*) = Mul 
    fromInteger = Const 
    abs = undefined 
    signum = undefined 
    negate = undefined 

instance IsString Expr where 
    fromString s = Var (head s) 

main = do 
    let expr = 3 * "x" + 2 * "y" :: Expr 
    print expr 
+0

. 고맙습니다. –

+0

방금 ​​네가'negate '에 대한 정의를 제공 할 수 있음을 깨달았다. - negate x = (-1) * x'. 불행히도 기본 정의 ('0-x')는 뺄셈이 없기 때문에 작동하지 않습니다. 또는'a - b = a + (-1) * b'을 정의하고 자유롭게'negate '할 수 있습니다. – ErikR

+0

소리가 깨끗합니다. 하지만'Negate' 타입의 생성자를'Expr'에 추가하면 어떻게 될까요? 'Mul (-1) ("x")'대신'Negate ("x")'를 갖는 장점/단점은 무엇입니까? 어떤 사람들은 그것을하는 것을 보았습니다, 그러나 나는 그 이유를 이해하지 못합니다. 'Expr'을 다루는 함수의 구현을 용이하게하는 것만 추측 할 수 있습니다. 예를 들어 '단순화'합니다. –

4

표현 데이터 유형에 대해 Num/Real의 인스턴스를 만들 수 있습니다. 끝내

instance Num Expr where 
    a + b = Add a b 
    a * b = Mul a b 
    fromIntegral a = Const a 

x = Var 'x' 
y = Var 'y' 

result = 2 * x + 3 * y 
관련 문제