我想编写一个兼具
的函数并确定给定值是否来自给定的构造函数。模式匹配似乎很适合这种情况,但匹配的模式必须是函数参数而不是硬编码的构造函数名称。
下面的代码就是我尝试过的,但是GHC在指示的行上报告了一个解析错误。
有没有办法实现这个目标?
data FooBar = Foo Int | Bar String
-- Imagine that these are useful functions.
processInt :: Int -> String
processInt = show
processString :: String -> String
processString = id
-- This should take one of the above functions and adapt it to operate on
-- FooBar values of compatible "type". Values that match the given FooBar
-- constructor should be "unwrapped" and passed to the given function.
typeCheck :: (a -> FooBar) -> (a -> String) -> (FooBar -> Maybe String)
typeCheck constructor func fooBar = case fooBar of
(constructor x) -> Just (func x) -- GHC says "Parse error in pattern: constructor"
_ -> Nothing
-- Define processing functions that operate on FooBars.
processFoo :: FooBar -> Maybe String
processFoo = typeCheck Foo processInt
processBar :: FooBar -> Maybe String
processBar = typeCheck Bar processString
答案 0 :(得分:3)
有趣的想法。我想知道你要做什么,因为这是一个非常不寻常的模式匹配问题。
如果可以,你当然可以这样做:
像这样(我打破了f
部分的应用,因为那是正交的):
wasBuilt :: Eq t => (t -> Either t t) -- ^ the constructor
-> Either t t -- ^ a value
-> Maybe t -- ^ the transformed result
wasBuilt k v = case v of
Left x | v == k x -> Just x
Right x | v == k x -> Just x
_ -> Nothing
但是有很多样板。这个问题在我身上尖叫着“generics”。尝试不同的方法,并将构造函数反映到数据,然后通常匹配该数据。这将允许您将构造函数视为值,而不是函数。
这大致是我的想法,但请注意,这是一项先进的技术。常规AST上的显式模式匹配更加惯用:
import Generics.SYB
-- only works for unary constructors
sameConstructor :: (Data a, Data b) => (a -> b) -> b -> Bool
sameConstructor k v = toConstr v == toConstr (k undefined)
> sameConstructor (Left :: Char -> Either Char Char) (Right 'x')
False
> sameConstructor (Left :: Char -> Either Char Char) (Left 'x')
True
> sameConstructor (:[]) "haskell"
True
答案 1 :(得分:2)
你可能想看看Type-safe pattern combinators功能性珍珠。虽然它没有与Haskell的模式匹配语法很好地混合,但它确实允许你具有可组合的一流模式的模块性,如果这是你需要的(即如果增加的可组合性超过语法上的不便)。