2

我有一个功能,dir_con :: (Int -> Dir)

我想进行模式匹配以查找 dir_con 是哪个特定的构造函数。数据类型为:

data Dir = Define Int
         | Equals Int 
         | Data Int  
         | LCset Int
         | NoArg Int

所以,dir_con 要么是Define,Equals等。它被传递给一个函数,我想像这样进行模式匹配:

case dir_con of
    NoArg -> Do something specific
    _     -> Do something for the rest

编译器不喜欢这样。错误信息是Couldn't match expected type 'Int -> Dir' with actual type 'Dir'

肯定NoArg是类型的构造函数(Int -> Dir)?Haskell 不允许这种类型的模式匹配吗?我必须这样做,因为Dir构造函数来自地图。有没有关于我可以如何NoArg区别对待的建议?

4

3 回答 3

5

两种方式:

case dir_con of
    NoArg _ -> Do something specific
    _     -> Do something for the rest

您匹配的是 /value/ 而不是构造函数。

或者,用户记录语法:

case dir_con of
    NoArg {} -> Do something specific
    _     -> Do something for the rest

这是良好的卫生习惯,因为它在字段数量方面是中性的。

于 2013-03-15T19:02:30.163 回答
4

您不能对函数进行模式匹配。type 的值Dir是通过应用几个构造函数之一来构建的,但dir_con它是 type 的函数Int -> Dir

您可能希望在模式匹配之前应用该函数:

case dir_con 7 of  -- `7` is just an arbitrary value I'm passing
  NoArg _ -> ...
  _       -> ...

此外,您还必须匹配NoArg构造函数的参数,否则在将参数添加到dir_con.

在您的具体情况下,您很可能不想传递文字整数,但可能是您从其他地方获得的参数:

myfun n = ... case dir_con n of
                NoArg _ -> ...
                _       -> ...
于 2013-03-15T19:12:05.017 回答
1

如果您的所有构造函数都是 type Int -> Dir,那么我建议与@hammar 相同:使构造函数类型为枚举:

data DirType = Define | Equals | Data | LCset | NoArg

data Dir = Dir DirType Int

然后你可能可以重构任何需要知道它是什么构造函数来使用DirType那里的值。

试图确定构造函数dir_con :: Int -> Dir是什么的基本问题是,并非该类型的所有内容都是构造函数。例如:

dispatch :: Int -> Dir
dispatch 0 = Define 0
dispatch 1 = Equals 1
dispatch n = NoArg n

对于“哪个构造函数”是没有好的答案dispatch

如果Dir是参数

data Dir a = Define a | Equals a | Data a | LCset a | NoArg a

然后有一种Dir构造函数;即forall a. a -> Dir a(您需要{-# LANGUAGE RankNTypes #-}扩展才能使用此类类型)。这种类型不允许dispatch检查其论点之类的恶作剧。因此,如果您有:

dir_con :: forall a. a -> Dir a

然后你可以通过传递一个微不足道的值来检查它的构造函数

case dir_con () of
    ...

即使您实际上只使用 a Dir Int,多态性也可以让您对您的类型更具描述性。

于 2013-03-15T22:26:24.877 回答