Dou*_*ean 28 haskell pattern-matching
Haskell中的vanilla数据类型具有零个或多个构造函数,每个构造函数都扮演两个角色.
在表达式中,它支持引入,它是从零个或多个参数到数据类型的函数.
在模式中,它支持消除,它有点像从数据类型到Maybe(参数类型的元组)的函数.
模块签名是否有可能在暴露后者时隐藏前者?
用例是这样的:我有一个类型T,它的构造函数类型有时可以用来构造废话.我有构造函数,可用于构建保证不是废话的类型的实例.在这种情况下隐藏构造函数是有意义的,但是对于调用者来说,能够通过构造函数构建的保证非废话模式匹配仍然是有用的.
我怀疑这是不可能的,但万一有人有办法做到这一点,我会问.
接下来最好的事情是隐藏构造函数并从T - > Maybe(This,That),T - > Maybe(The,Other,Thing)等创建一堆函数.
Lam*_*eek 38
您可以使用视图类型和视图模式来执行您想要的操作:
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
Run Code Online (Sandbox Code Playgroud)
请注意,这ThingView不是递归数据类型:所有值构造函数都会引用Thing.所以现在你可以导出值构造函数ThingView并保持Thing抽象.
使用这样:
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> FooV x) = doSomethingWithThing x
doSomethingWithThing(view -> BarV y) = y
Run Code Online (Sandbox Code Playgroud)
箭头符号的东西是GHC的View Patterns.请注意,它需要语言编译指示.
当然你不需要使用视图模式,你可以手工完成所有的desugaring:
doSomethingWithThing :: Thing -> Int
doSomethingWithThing = doIt . view
where doIt (FooV x) = doSomethingWithThing x
doIt (BarV y) = y
Run Code Online (Sandbox Code Playgroud)
其实我们可以做的更好一点:没有理由重复所有这两个值构造Thing和ThingView
module ThingModule (ThingView(..), Thing, view) where
newtype Thing = T {view :: ThingView Thing}
data ThingView a = Foo a | Bar Int
Run Code Online (Sandbox Code Playgroud)
继续像以前一样使用它,但现在模式匹配可以使用Foo和Bar.
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> Foo x) = doSomethingWithThing x
doSomethingWithThing(view -> Bar y) = y
Run Code Online (Sandbox Code Playgroud)
Joa*_*ner 24
从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
Run Code Online (Sandbox Code Playgroud)
和
{-# LANGUAGE PatternSynonyms #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing (Foo x) = doSomethingWithThing x
doSomethingWithThing (Bar y) = y
Run Code Online (Sandbox Code Playgroud)
所以它看起来像普通的构造函数.
如果你试图用来Bar构造一个值,那么你就得到了
Main.hs:9:32:
Bar used in an expression, but it's a non-bidirectional pattern synonym
In the expression: Bar y
Run Code Online (Sandbox Code Playgroud)
你不能.但是如果你的类型T只有合理数量的构造函数,你可能想要隐藏构造函数,而是提供一个函数,它以与之相同的精神进行模式匹配maybe :: b -> (a -> b) -> Maybe a -> b.