在Haskell模块中,是否可以导出构造函数进行模式匹配,但是不能构造? [英] Is it possible to export constructors for pattern matching, but not for construction, in Haskell Modules?

查看:110
本文介绍了在Haskell模块中,是否可以导出构造函数进行模式匹配,但是不能构造?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Haskell中的vanilla数据类型有零个或多个构造函数,每个构造函数都扮演两个角色。



在表达式中,它支持引入,它是一个从零开始的函数,或者在数据类型中有更多的参数。

在模式中,它支持消除,它类似于从数据类型到Maybe(参数类型的元组)的函数。



模块签名可能在隐藏前者时隐藏前者?

用例如下:I有一个类型T,它的构造函数类型有时可以用来构造废话。我有构建函数可用于构建类型的实例,保证不是废话。在这种情况下隐藏构造函数是有意义的,但对于调用者来说,它们仍然可以在构造函数构建的保证非废话时进行匹配。



我怀疑这是不可能的,但如果有人有办法做到这一点,我可以问。

接下来最好的办法是隐藏构造函数,并从T - > Maybe(This,That),T - > Maybe(The,Other,Thing)等创建一组函数。方案

您可以使用视图类型视图模式完成您想要的任务:

  module ThingModule(Thing,ThingView(..),view)其中

数据Thing = Foo Thing | Bar Int

数据ThingView = FooV Thing | BarV Int

view :: Thing - > ThingView
view(Foo x)= FooV x
view(Bar y)= BarV y

请注意, ThingView 不是递归数据类型:所有值构造函数都引用 Thing 。因此,现在您可以导出 ThingView 的值构造函数,并保留 Thing abstract。



使用像这样:

  { - #LANGUAGE ViewPatterns# - } 
module Main其中

导入ThingModule

doSomethingWithThing :: Thing - > Int
doSomethingWithThing(view - > FooV x)= doSomethingWithThing x
doSomethingWithThing(view - > BarV y)= y

箭头符号是GHC的查看模式。请注意,它需要一个语言编译指示。



当然你不需要使用视图模式,你可以手动完成所有的desugaring:

  doSomethingWithThing :: Thing  - > Int 
doSomethingWithThing = doIt。查看
其中doIt(FooV x)= doSomethingWithThing x
doIt(BarV y)= y



更多



实际上我们可以做得更好一点:没有理由复制 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模块中,是否可以导出构造函数进行模式匹配,但是不能构造?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆