Data.Typeable.TypeRep上的模式匹配和案例表达问题

时间:2016-08-22 14:24:06

标签: haskell pattern-matching

我正在尝试在以下代码中对Data.Typeable.TypeRep进行模式匹配:

import Data.Typeable (TypeRep, typeOf)

tyI = typeOf (1    :: Int)
tyD = typeOf (3.14 :: Double)
tyB = typeOf (True :: Bool)

func1 :: TypeRep -> Bool
func1 tyI = False
func1 tyD = False
func1 _ = True

func2 :: TypeRep -> Bool
func2 tr = case tr of
    tyI -> False
    tyD -> False
    _   -> True

func3 :: TypeRep -> Bool
func3 tr = if tr == tyI then False else
           if tr == tyD then False else
           True

...我在编译时收到这些警告:

[1 of 1] Compiling Main             ( /home/[..]/test.hs, interpreted )

/home/[..]/test.hs:8:1: Warning:
    Pattern match(es) are overlapped
    In an equation for ‘func1’:
        func1 tyD = ...
        func1 _ = ...

/home/[..]/test.hs:23:12: Warning:
    Pattern match(es) are overlapped
    In a case alternative:
        tyD -> ...
        _ -> ...
Ok, modules loaded: Main.

另外,我得到了令人惊讶的结果:

*Main> func1 tyI
False
*Main> func1 tyD
False
*Main> func1 tyB
False -- !!!

*Main> func2 tyI
False
*Main> func2 tyD
False
*Main> func2 tyB
False -- !!!

*Main> func3 tyI
False
*Main> func3 tyD
False
*Main> func3 tyB
True -- Ok!

所以只有最后一个函数func3似乎产生了预期的结果。如何使用模式匹配(func1)和case(func2)函数在TypeReps上正常工作?

2 个答案:

答案 0 :(得分:3)

问题是在模式匹配中tyItyD被视为普通变量(而不是与同名的全局常量进行比较)。以下代码完全等同于您的代码。

func1 :: TypeRep -> Bool
func1 x = False
func1 y = False
func1 _ = True

func2 :: TypeRep -> Bool
func2 tr = case tr of
    x -> False
    y -> False
    _ -> True

正如您在func3中观察到的那样,解决此问题的方法是明确比较。您也可以使用警卫:

func4 :: TypeRep -> Bool
func4 tr | tr == tyI = False
         | tr == tyD = False
         | otherwise = True

通常,构造函数中可以匹配的equals左侧允许的唯一内容是构造函数。一个例外是数字文字,您会注意到在模式中使用这些文字会对整个函数产生Eq约束

even :: (Num a, Eq a) => a -> Bool
even 0 = True
even 1 = False
even n = even (n-2)

如果添加OverloadedListsOverloadedStrings,则会添加此规则的类似例外情况。该规则几乎适用于所有情况。

答案 1 :(得分:3)

此处tyI

func1 :: TypeRep -> Bool
func1 tyI = False

与此处定义的tyI无关:

tyI = typeOf (1    :: Int)

事实上,您对func1的定义可以写成:

func1 :: TypeRep -> Bool
func1 x = False

同样适用于func2 - 变量tyItyBtyD只有模式变量名称,并且不引用您的全局绑定。

但是,您在tyI中对tyDfunc3的使用确实引用了全局定义,因此func3 tyB返回True的原因。