[英]Is it possible to export constructors for pattern matching, but not for construction, in Haskell Modules?
Haskell中的vanilla数据类型具有零个或多个构造函数,每个构造函数都扮演两个角色。
在表达式中,它支持引入,它是从零个或多个参数到数据类型的函数。
在模式中,它支持消除,它有点像从数据类型到Maybe(参数类型的元组)的函数。
模块签名是否有可能在暴露后者时隐藏前者?
用例是这样的:我有一个类型T,它的构造函数类型有时可以用来构造废话。 我有构造函数,可用于构建保证不是废话的类型的实例。 在这种情况下隐藏构造函数是有意义的,但是对于调用者来说,能够通过构造函数构建的保证非废话模式匹配仍然是有用的。
我怀疑这是不可能的,但万一有人有办法做到这一点,我会问。
接下来最好的事情是隐藏构造函数并从T - > Maybe(This,That),T - > Maybe(The,Other,Thing)等创建一堆函数。
您可以使用视图类型和视图模式来执行您想要的操作:
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
请注意, ThingView
不是递归数据类型:所有值构造函数都引用回Thing
。 所以现在你可以导出ThingView
的值构造ThingView
并保持Thing
抽象。
使用这样:
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> FooV x) = doSomethingWithThing x
doSomethingWithThing(view -> BarV y) = y
箭头符号的东西是GHC的View Patterns 。 请注意,它需要语言编译指示。
当然你不需要使用视图模式,你可以手工完成所有的desugaring:
doSomethingWithThing :: Thing -> Int
doSomethingWithThing = doIt . view
where doIt (FooV x) = doSomethingWithThing x
doIt (BarV y) = y
实际上我们可以做得更好一点:没有理由复制Thing
和ThingView
所有值构造ThingView
module ThingModule (ThingView(..), Thing, view) where
newtype Thing = T {view :: ThingView Thing}
data ThingView a = Foo a | Bar Int
继续使用它与以前一样,但现在模式匹配可以使用Foo
和Bar
。
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> Foo x) = doSomethingWithThing x
doSomethingWithThing(view -> Bar y) = y
从GHC 7.8开始,您可以使用PatternSynonyms
来导出独立于构造函数的模式。 所以类似@ Lambdageek的答案就是
{-# LANGUAGE PatternSynonyms #-}
module ThingModule (Thing, pattern Foo, pattern Bar) where
pattern Foo a <- RealFoo a
pattern Bar a <- RealBar a
data Thing = RealFoo Thing | RealBar Int
和
{-# LANGUAGE PatternSynonyms #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing (Foo x) = doSomethingWithThing x
doSomethingWithThing (Bar y) = y
所以它看起来像普通的构造函数。
如果你试图使用Bar
来构造一个值,那么你就得到了
Main.hs:9:32:
Bar used in an expression, but it's a non-bidirectional pattern synonym
In the expression: Bar y
你不能。 但是如果你的类型T只有合理数量的构造函数,你可能想要隐藏构造函数,而是提供一个函数,它以与maybe :: b -> (a -> b) -> Maybe a -> b
相同的精神进行模式匹配maybe :: b -> (a -> b) -> Maybe a -> b
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.