簡體   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