如果我有一个构造函数:
data Garage = Gar String
如果我想测试一个类型是否等于我的车库类型,我会做这样的事情:
(==(Gar _)) (Gar "g")
然而,编译器抱怨下划线。如果我将其替换为"g"
,则返回True
。有没有办法让我可以与通配符进行比较?
答案 0 :(得分:4)
为什么您的代码无效?
您希望模式匹配,但实际上您正在使用参数==
和Gar _
调用函数Gar "g"
。因此,Haskell感到困惑,并在表达式上下文中说出" Pattern语法:_"。
如何解决?
你可以:
将deriving Eq
添加到数据声明的末尾,或
自己实施Eq
:
instance Eq Garage where
(Gar l) == (Gar r) = l == r
是否可以对构造函数通配符进行模式匹配?(为了完整性)
是的,这是一个无意义的功能:
f :: Garage -> Int
f (Gar "abc") = 12
f (Gar _) = 4
但是,对于具有多个构造函数的数据类型,这可能会更有用。
答案 1 :(得分:2)
你想进行模式匹配,如下所示:
case x of
Gar _ -> True
_ -> False
如果你想要它作为函数,那么添加像
这样的东西isGarage (Gar _) = True
isGarage _ = False
答案 2 :(得分:0)
也许你的问题假定你需要在Haskell中进行运行时类型检查,但这不是必需的。 Haskell将确保所有类型在编译时都是正确的,因此不需要检查数据是否属于Garage
数据类型的函数,并且不起作用:
justPrintGarages (Gar x) = print x -- if the argument is a Garage, print its content
justPrintGarages _ = return () -- if it's anything else, do nothing.
如果我们问ghci justPrintGarages
有什么类型,它会告诉我们
printGarages :: Garage -> IO ()
糟糕!我们的功能应该告诉我们我们是否只有一个车库才能在车库上工作???对。那是因为Haskell故意阻止你混合类型,因为它是运行时错误的泥潭。静态打字是你的朋友。静态打字带走了一个痛苦的世界。由于静态类型,您无法定义
printGaragesAndShebangs (Gar x) = print x
printGaragesAndShebangs ('#':'!':xs) = putStr xs
printGaragesAndShebangs _ = return ()
您将收到类型错误。您不能只将String
和Garage
视为相同。
如果你想混合车库和琴弦,这就是这样做的方法,保持类型安全:
data GarageStringInt = GsiG Garage | GsiS String | GsiI Int
(GarageStringInt
是一个可怕的名字,GisG
等也是如此,但是如果你在代码中需要它,那么它代表了一些明智的东西(我希望),你可以给它一个名称来描述它它代表什么。)
现在我们可以写
printGaragesAndShebangs :: GarageStringInt -> IO ()
printGaragesAndShebangs (GsiG (Gar x)) = print x
printGaragesAndShebangs (GsiS ('#':'!':xs)) = putStr xs
printGaragesAndShebangs _ = return ()
答案 3 :(得分:0)
像
这样的功能isGarage (Gar _) = True
isGarage _ = False
非常无用,因为它的类型为Garage -> Bool
。因此,对于True
类型,它将始终返回Garage
,并且对于任何其他类型,将发生类型检查失败。
我认为模式匹配足以满足您的要求。但只是为了表明如果你知道你将要采用的类型,你可以使用类型类来实现这种功能。因此,如果你知道你将获得一组给定类型的值,那么你可以做类似的事情
{-# LANGUAGE FlexibleInstances #-}
data Garage = Gar String
class IsGarage a where
isGarage :: a -> Bool
isGarage _ = False
instance IsGarage Garage where
isGarage _ = True
instance IsGarage [Char]
在ghci
*Main> :t isGarage
isGarage :: IsGarage a => a -> Bool
*Main> isGarage "3"
False
*Main> isGarage (Gar "2")
True