构造函数通配符上的模式匹配?

时间:2012-09-20 20:28:23

标签: haskell pattern-matching

如果我有一个构造函数:

data Garage = Gar String

如果我想测试一个类型是否等于我的车库类型,我会做这样的事情:

(==(Gar _)) (Gar "g")

然而,编译器抱怨下划线。如果我将其替换为"g",则返回True。有没有办法让我可以与通配符进行比较?

4 个答案:

答案 0 :(得分:4)

为什么您的代码无效?

您希望模式匹配,但实际上您正在使用参数==Gar _调用函数Gar "g"。因此,Haskell感到困惑,并在表达式上下文中说出" Pattern语法:_"。

如何解决?

你可以:

  1. deriving Eq添加到数据声明的末尾,或

  2. 自己实施Eq

    instance Eq Garage where
        (Gar l) == (Gar r) = l == r
    
  3. 是否可以对构造函数通配符进行模式匹配?(为了完整性)

    是的,这是一个无意义的功能:

    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 ()

您将收到类型错误。您不能只将StringGarage视为相同。

如果你想混合车库和琴弦,这就是这样做的方法,保持类型安全:

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