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