Is it possible to export constructors for pattern matching, but not for construction, in Haskell Modules?

前端 未结 3 552
予麋鹿
予麋鹿 2020-12-05 07:03

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 mo

3条回答
  •  执念已碎
    2020-12-05 07:34

    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
    

提交回复
热议问题