我试图以一种通用的方式匹配数据构造函数,以便执行任何特定类型的任务。
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使用一个字符串作为(*>)的参数,因此匹配完全使用字符串匹配。我想做这件事而不需要附加条件。
发布于 2013-07-19 20:11:24
您的直觉是正确的,不可能像您指定的那样编写(#>)。数据构造函数充当模式的唯一时间是当它处于模式位置时,即作为函数的参数出现。
f (TaskTypeA z) = ...作为case语句的替代方案之一。
case tt of
TaskTypeA z -> ...或在一元或模式绑定中
do TaskTypeA z <- Just tt
return z当它被用于价值位置(例如,作为一个函数的参数)时,它就失去了它的模式性质,成为一个正规的函数。这意味着,不幸的是,您不能这么容易地抽象模式。
然而,有一个简单的模式正规化:
type Pattern d a = d -> Maybe a这是一点点的工作,以使他们。
taskTypeA :: Pattern Task Int
taskTypeA (TaskTypeA z) = Just z
taskTypeA _ = Nothing如果还需要使用构造函数“转发”(即a -> d),则可以将两者配对(加上一些函数来处理):
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和它的两个助手函数可以用一个小技巧等价地编写:
data Constructor d a = Constructor { apply :: a -> d, match :: d -> Maybe a })
有了这个抽象,现在就可以编写(#>)了。一个简单的例子是
(#>) :: Constructor d a -> (a -> State d ()) -> State d ()
cons #> f = do
d <- get
case match cons d of
Nothing -> return ()
Just a -> f a或者更复杂的东西,取决于你到底想要什么。
https://stackoverflow.com/questions/17747927
复制相似问题