本文介绍了在Haskell模块中,是否可以导出构造函数进行模式匹配,但是不能构造?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
Haskell中的vanilla数据类型有零个或多个构造函数,每个构造函数都扮演两个角色。
在表达式中,它支持引入,它是一个从零开始的函数,或者在数据类型中有更多的参数。
在模式中,它支持消除,它类似于从数据类型到Maybe(参数类型的元组)的函数。
模块签名可能在隐藏前者时隐藏前者?
用例如下:I有一个类型T,它的构造函数类型有时可以用来构造废话。我有构建函数可用于构建类型的实例,保证不是废话。在这种情况下隐藏构造函数是有意义的,但对于调用者来说,它们仍然可以在构造函数构建的保证非废话时进行匹配。
我怀疑这是不可能的,但如果有人有办法做到这一点,我可以问。
接下来最好的办法是隐藏构造函数,并从T - > Maybe(This,That),T - > Maybe(The,Other,Thing)等创建一组函数。方案
您可以使用视图类型和视图模式完成您想要的任务:
的所有值构造函数。 code>和 ThingView 模块ThingModule(ThingView 。),Thing,view)其中
newtype Thing = T {view :: ThingView Thing}
数据ThingView a = Foo a | Bar Int
继续像以前一样使用它,但现在模式匹配可以使用 Foo 和 Bar 。
{ - #LANGUAGE ViewPatterns# - }
module Main其中
import ThingModule
doSomethingWithThing :: Thing - > Int
doSomethingWithThing(view - > Foo x)= doSomethingWithThing x
doSomethingWithThing(view - > Bar y)= y
A vanilla data type in Haskell has zero or more constructors, each of which plays two roles.
In expressions, it supports introduction, its a function from zero or more arguments to the data type.
In patterns, it supports elimination, its kinda like a function from the data type to Maybe (tuple of argument types).
Is it possible for a module signature to hide the former while exposing the latter?
The use case is this: I have a type, T, whose constructors types alone can sometimes be used to construct nonsense. I have construction functions which can be used to build instances of the type that are guaranteed not to be nonsense. It would make sense to hide the constructors in this case, but it would still be useful for callers to be able to pattern match over the guaranteed-non-nonsense that they build with the construction functions.
I suspect this is impossible, but in case anyone has a way to do it, I though I would ask.
Next best thing is to hide the constructors and create a bunch of functions from T -> Maybe (This, That), T -> Maybe (The, Other, Thing), etc.
解决方案
You can use a view type and view patterns to do what you want:
module ThingModule (Thing, ThingView(..), view) where
data Thing = Foo Thing | Bar Int
data ThingView = FooV Thing | BarV Int
view :: Thing -> ThingView
view (Foo x) = FooV x
view (Bar y) = BarV y
Note that ThingView is not a recursive data type: all the value constructors refer back to Thing. So now you can export the value constructors of ThingView and keep Thing abstract.
Use like this:
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> FooV x) = doSomethingWithThing x
doSomethingWithThing(view -> BarV y) = y
The arrow notation stuff is GHC's View Patterns. Note that it requires a language pragma.
Of course you're not required to use view patterns, you can just do all the desugaring by hand:
doSomethingWithThing :: Thing -> Int
doSomethingWithThing = doIt . view
where doIt (FooV x) = doSomethingWithThing x
doIt (BarV y) = y
More
Actually we can do a little bit better: There is no reason to duplicate all the value constructors for both Thing and ThingView
module ThingModule (ThingView(..), Thing, view) where
newtype Thing = T {view :: ThingView Thing}
data ThingView a = Foo a | Bar Int
Continue useing it the same way as before, but now the pattern matches can use Foo and Bar.
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> Foo x) = doSomethingWithThing x
doSomethingWithThing(view -> Bar y) = y
这篇关于在Haskell模块中,是否可以导出构造函数进行模式匹配,但是不能构造?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!