在Haskell中使用参数作为模式

alt*_*ler 12 haskell pattern-matching

是否有可能创建一个泛型函数,将Foo或Bar作为参数,并返回一个在模式匹配中使用该参数的函数?

例如,如果我有

isFoo :: SomeData -> Bool
isFoo (Foo _) = True
isFoo _       = False

isBar :: SomeData -> Bool
isBar (Bar _) = True
isBar _       = False
Run Code Online (Sandbox Code Playgroud)

有没有办法创建一个通用函数,如

checkType :: SomeClass -> SomeData -> Bool
checkType (SomeClass _) = True
checkType _ = False
Run Code Online (Sandbox Code Playgroud)

我意识到情况看起来有点奇怪,实际的用例有点复杂,但问题是相同的.


我正在尝试重构的实际代码如下

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
Run Code Online (Sandbox Code Playgroud)

所以我想用一些方法让它更干燥

dan*_*iaz 27

Prism来自lens图书馆的s可以充当"一流的模式".要为您的数据类型定义棱镜:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data SomeData = Foo Int 
              | Bar Char

-- Will create prisms named _Foo and _Bar
$(makePrisms ''SomeData)
Run Code Online (Sandbox Code Playgroud)

由于Prisms是有效的Folds,我们可以将它们传递给has函数Control.Lens.Fold:

*Main> has _Foo (Foo 5)
True
*Main> has _Bar (Foo 5)
False
Run Code Online (Sandbox Code Playgroud)

棱镜作为第一类模式的另一个有趣的应用是"覆盖"函数的行为,用于参数与棱镜匹配的情况.您可以使用outsidefrom Control.Lens.Prism来做到这一点.outside是一个函数,它接受Prism并返回一个Lensfor函数,允许你"设置"特殊情况.例如:

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
Run Code Online (Sandbox Code Playgroud)

测试这两个功能:

*Main> functionToOverride (Foo 77)
5
*Main> newFunction (Bar 'a')
5
*Main> newFunction (Foo 77)
78
Run Code Online (Sandbox Code Playgroud)