繁体   English   中英

在Haskell模块中是否可以导出构造函数以进行模式匹配,但不能用于构造?

[英]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

更多

实际上我们可以做得更好一点:没有理由复制ThingThingView所有值构造ThingView

module ThingModule (ThingView(..), Thing, view) where

   newtype Thing = T {view :: ThingView Thing}
   data ThingView a = Foo a | Bar Int

继续使用它与以前一样,但现在模式匹配可以使用FooBar

{-# 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM