省略一元制造者

时间:2014-04-30 15:09:02

标签: haskell

我正在写一些代码来表达"表达式"从给定类型的成员构建:

data Expr a = Simply a | Add (Expr a, Expr a) | Mult (Expr a, Expr a) 

可以定义一些中缀运算符,以便更方便地构造它们:

(+++) :: Expr a -> Expr a -> Expr a
x +++ y = Add (x, y)

(***) :: Expr a -> Expr a -> Expr a
x *** y = Mult (x, y)

因此可以写

(Simply "bar") +++ ((Simply "fo") *** (Simply "o"))

获取

Add (Simply "bar",Mult (Simply "fo",Simply "o"))

现在的问题是,是否有办法省略构造函数Simply,即将[{1}}类型的任何成员隐式地视为a的成员并获取以上示例直接来自Expr a

3 个答案:

答案 0 :(得分:10)

您可以创建这样的表达式:

class IsExpr a b | a -> b where 
      ex :: a -> Expr b

这定义了一类类型a,它们是类型b的表达式,其中b被声明为由使用函数依赖项确定。

然后继续将String变为Expr String类型的表达式:

instance IsExpr String String where
     ex = Simply

此外,有些不足为奇的是,表达式也是表达式:

instance IsExpr (Expr a) a where
     ex = id

现在您可以重新定义您的运算符,以便它们可以采用任何产生相同类型表达式的事物的组合,即任何参数可以是StringExpr String或您定义的任何{{1} 1}}实例:

IsExpr

这确实需要一些扩展:(++++) :: (IsExpr a c, IsExpr b c) => a -> b -> Expr c x ++++ y = Add (ex x, ex y) (****) :: (IsExpr a c, IsExpr b c) => a -> b -> Expr c x **** y = Mult (ex x, ex y) (仅当您使用TypeSynonymInstances s),StringFlexibleInstancesMultiParamTypeClasses时。当然,存在复杂性/收益权衡,因此可能不会带来额外的复杂性。

顺便说一下,我宁愿将数据构造函数定义为FunctionalDependencies。你正在添加一个  通过使用元组来增加间接性。

答案 1 :(得分:3)

您可以使用Simply扩展程序删除-XOverloadedStrings构造函数。

 {-# LANGUAGE OverloadedStrings, FlexibleInstances #-}
 import Data.String

 instance IsString (Expr String) where
   fromString = Simply

然后创建一个Num实例以获取普通运算符

 instance Num (Expr a) where
  (+) = curry Add
  (*) = curry Mult

然后你可以做像

这样的事情
"foo" + "bar" + "baz" :: Expr String

所有这一切都是因为GHC将"..."解释为fromString "..."

答案 2 :(得分:2)

如果你坚持在字符串上使用数学运算符,你可以使Expr a成为Num类的实例:使用这些操作创建一个新的类型类:

{-# LANGUAGE TypeFamilies #-}

class ExprOps a where
   type Internal a
   (+++) :: a -> a -> a
   (***) :: a -> a -> a
   fromInternal :: Internal a -> a

instance ExprOps (Expr a) where
  type Internal (Expr a) = a
  x +++ y = Add (x,y)
  x *** y = Mult (x,y)
  fromInternal = Simply

然后你可以简单地写

foo :: Expr String
foo = "bar" +++ "fo" *** "o"

仍然会产生表达式

Add (Simply "bar",Mult (Simply "fo",Simply "o"))

但不需要任何明确的Simply构造函数。