是否可以制作一个将Foo或Bar作为参数并返回在其模式匹配中使用该参数的函数的泛型函数?
例如,如果我有
isFoo :: SomeData -> Bool
isFoo (Foo _) = True
isFoo _ = False
isBar :: SomeData -> Bool
isBar (Bar _) = True
isBar _ = False
有没有一种创建通用函数的方法,例如
checkType :: SomeClass -> SomeData -> Bool
checkType (SomeClass _) = True
checkType _ = False
我意识到情况看起来有些奇怪,实际用例要复杂一些,但是问题是相同的。
我尝试重构的实际代码如下
isString :: [LispVal] -> ThrowsError LispVal
isString [(String _)] = return $ Bool True
isString ((String _):xs) = isString xs >>= unpackBool >>= return . Bool
isString _ = return $ Bool False
isSymbol :: [LispVal] -> ThrowsError LispVal
isSymbol [(Atom _)] = return $ Bool True
isSymbol ((Atom _):xs) = isSymbol xs >>= unpackBool >>= return . Bool
isSymbol _ = return $ Bool False
isNumber :: [LispVal] -> ThrowsError LispVal
isNumber [(Number _)] = return $ Bool True
isNumber ((Number _):xs) = isNumber xs >>= unpackBool >>= return . Bool
isNumber _ = return $ Bool False
所以我想用某种方法使它更干燥
最佳答案
Prism
s库中的 lens
可以充当“一流模式”。为您的数据类型定义棱镜:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data SomeData = Foo Int
| Bar Char
-- Will create prisms named _Foo and _Bar
$(makePrisms ''SomeData)
由于
Prism
是有效的Fold
,因此我们可以将它们从has
传递给 Control.Lens.Fold
函数:*Main> has _Foo (Foo 5)
True
*Main> has _Bar (Foo 5)
False
棱镜作为一流模式的另一个有趣应用是在参数与棱镜匹配的情况下“覆盖”函数的行为。您可以使用
outside
中的 Control.Lens.Prism
来做到这一点。 outside
是一个函数,它接受一个Prism
并返回该函数的Lens
,这使您可以“设置”特殊情况。例如:functionToOverride :: SomeData -> Int
functionToOverride = const 5
-- If the arg is a Foo, return the contained int + 1
newFunction :: SomeData -> Int
newFunction = functionToOverride & outside _Foo .~ succ
测试两个功能:
*Main> functionToOverride (Foo 77)
5
*Main> newFunction (Bar 'a')
5
*Main> newFunction (Foo 77)
78