我有两个变量,
let x = 3
let y = 4
我有一堆形式为加号、减号、Lt、Gt、Gte等的运算符。
data Operator = Plus | Minus | Divide | Gt | Lt ....
我正在尝试编写一个函数,该函数接受运算符类型并返回实际运算符。类似:
returnOperator :: Operator -> (Int->Int->a)
returnOperator op = case op of
Plus -> (+)
Minus -> (-)
Gt -> (>)
...etc
所以我可以做:
let output_op = returnOperator (Plus)
let z = x `output_op` y
z = 7
举个例子。然而,我写的returnOperator函数给出了一个错误:
Couldn't match type ‘a’ with ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
returnOp :: forall a. Operator -> Int -> Int -> a
关于如何解决这个问题,有什么建议吗?
一种方法是按类型分隔运算符。
data BoolOperator = Gt | Lt | ...
data IntOperator = Plus | Minus | Divide | ...
boolOp :: BoolOperator -> Int -> Int -> Bool
intOp :: IntOperator -> Int -> Int -> Int
一种更先进的方法是使用GADT,其边际效用值得怀疑。
data Operator a where
Plus :: Operator Int
Gt :: Operator Bool
returnOperator :: Operator a -> Int -> Int -> a
returnOperator Plus = (+)
returnOperator Gt = (<)
请注意,这并不像你一开始想象的那样给你带来好处;特别地,任何同构的数据结构,如列表或Map
s,都不能同时存储Plus
和Gt
,因为它们具有不同的类型。