Extending a datatype in Haskell

后端 未结 4 1312
夕颜
夕颜 2020-12-31 08:33

Haskell newbie here.

I wrote an evaluator for a minimal assembly-like language.

Now, I want to extend that language to support some syntactic sugar which,

4条回答
  •  醉话见心
    2020-12-31 09:31

    This problem was named "the expression problem" by Phil Wadler, in his words:

    The goal is to define a data type by cases, where one can add new cases to the data type and new functions over the data type, without recompiling existing code, and while retaining static type safety.

    One solution to have extensible data type is to use type classes.

    As an example let's assume we have a simple language for arithmetics:

    data Expr = Add Expr Expr | Mult Expr Expr | Const Int
    
    run (Const x) = x
    run (Add exp1 exp2)  = run exp1 + run exp2
    run (Mult exp1 exp2) = run exp1 * run exp2
    

    e.g.

    ghci> run (Add (Mult (Const 1) (Const 3)) (Const 2))
    5
    

    If we wanted to implement it in an extensible way, we should switch to type classes:

    class Expr a where
        run :: a -> Int
    
    
    data Const = Const Int
    
    instance Expr Const where
        run (Const x) = x
    
    
    data Add a b = Add a b
    
    instance (Expr a,Expr b) => Expr (Add a b) where
        run (Add expr1 expr2) = run expr1 + run expr2
    
    
    data Mult a b = Mult a b
    
    instance (Expr a, Expr b) => Expr (Mult a b) where
        run (Mult expr1 expr2) = run expr1 * run expr2
    

    Now let's extend the language adding subtractions:

    data Sub a b = Sub a b
    
    instance (Expr a, Expr b) => Expr (Sub a b) where
        run (Sub expr1 expr2) = run expr1 - run expr2
    

    e.g.

    ghci> run (Add (Sub (Const 1) (Const 4)) (Const 2))
    -1
    

    For more info on this approach, and in general on the expression problem, check Ralf Laemmel's videos 1 and 2 on Channel 9.

    However, as noticed in the comments, this solution changes the semantics. For example lists of expressions are no longer legal:

    [Add (Const 1) (Const 5), Const 6] -- does not typecheck
    

    A more general solution using coproducts of type signatures is presented in the functional pearl "Data types a la carte". See also Wadler's comment on the paper.

提交回复
热议问题