首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >匹配数据构造函数

匹配数据构造函数
EN

Stack Overflow用户
提问于 2013-07-19 13:55:45
回答 1查看 1.1K关注 0票数 2

我试图以一种通用的方式匹配数据构造函数,以便执行任何特定类型的任务。

代码语言:javascript
复制
data Task = TaskTypeA Int | TaskTypeB (Float,Float)

genericTasks :: StateLikeMonad s
genericTasks = do
   want (TaskTypeA 5)

   TaskTypeA #> \input -> do 
       want (TaskTypeB (1.2,4.3))
       runTaskTypeA input

   TaskTypeB #> \(x,y) -> runTaskTypeB x y

main = runTask genericTasks

在这个过程中,genericTasks函数通过do指令,从由某种状态monad处理的want构建要做的事情的列表,以及通过(#>)函数进行处理的方法列表。runTask函数将运行genericTasks,使用要做和如何做的结果列表,并进行计算。

但是,我在弄清楚如何从(TaskTypeA,B)中提取"type“(#>)时遇到了一些麻烦,以便以后可以调用它。如果你做了一个:t TaskTypeA,你就会得到一个Int -> Task

例如,如何编写(#>)**?**

我也不完全相信,它是有可能的,我在这里的想法,在这样一个通用的方式。作为参考,我试图构建类似于Shake库的东西,其中(#>)类似于(*>)。但是,Shake使用一个字符串作为(*>)的参数,因此匹配完全使用字符串匹配。我想做这件事而不需要附加条件。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-19 20:11:24

您的直觉是正确的,不可能像您指定的那样编写(#>)。数据构造函数充当模式的唯一时间是当它处于模式位置时,即作为函数的参数出现。

代码语言:javascript
复制
f (TaskTypeA z) = ...

作为case语句的替代方案之一。

代码语言:javascript
复制
case tt of
    TaskTypeA z -> ...

或在一元或模式绑定中

代码语言:javascript
复制
do TaskTypeA z <- Just tt
   return z

当它被用于价值位置(例如,作为一个函数的参数)时,它就失去了它的模式性质,成为一个正规的函数。这意味着,不幸的是,您不能这么容易地抽象模式。

然而,有一个简单的模式正规化:

代码语言:javascript
复制
type Pattern d a = d -> Maybe a

这是一点点的工作,以使他们。

代码语言:javascript
复制
taskTypeA :: Pattern Task Int
taskTypeA (TaskTypeA z) = Just z
taskTypeA _ = Nothing

如果还需要使用构造函数“转发”(即a -> d),则可以将两者配对(加上一些函数来处理):

代码语言:javascript
复制
data Constructor d a = Constructor (a -> d) (d -> Maybe a)

apply :: Constructor d a -> a -> d
apply (Constructor f _) = f

match :: Constructor d a -> d -> Maybe a
match (Constructor _ m) = m

taskTypeA :: Constructor Task Int
taskTypeA = Constructor TaskTypeA $ \case TaskTypeA z -> Just z
                                          _ -> Nothing

这被称为“棱镜”,(一种非常普遍的形式)它是在透镜中实现的。

使用这样的抽象是有好处的--也就是说,您可以构造结构可能比数据类型允许的更多的棱镜(例如,d可以是函数类型),您可以编写对构造函数进行操作的函数,合成更简单的函数,使更复杂的函数泛化。

但是,如果您使用的是普通数据类型,那么必须为每个构造函数实现Constructor对象是件很痛苦的事,就像我在上面为TaskTypeA做的那样。如果您有很多这些需要处理,您可以使用模板Haskell为您编写样板。必要的模板Haskell例程是镜头中的已实施 --因此学习如何使用镜头库可能是值得的。(但这可能有点令人望而生畏)

(样式注意:上面的第二个Constructor和它的两个助手函数可以用一个小技巧等价地编写:

代码语言:javascript
复制
data Constructor d a = Constructor { apply :: a -> d, match :: d -> Maybe a }

)

有了这个抽象,现在就可以编写(#>)了。一个简单的例子是

代码语言:javascript
复制
(#>) :: Constructor d a -> (a -> State d ()) -> State d ()
cons #> f = do
    d <- get
    case match cons d of
        Nothing -> return ()
        Just a  -> f a

或者更复杂的东西,取决于你到底想要什么。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17747927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档