[Haskell-cafe] How to specialize a type

Ruben Astudillo ruben.astud at gmail.com
Sat Oct 17 16:28:06 UTC 2015


On 17/10/15 07:40, martin wrote:
> Am 10/17/2015 um 08:08 AM schrieb Ruben Astudillo:
>
>> This just seems a trade-off if you want to know with what are you dealing
>> just matching the outer constructor or more of the problem won't care
>> about it. Not really a dichotomy worth caring about much anyways
>
> I'll have to think about this. Wouldn't this be a problem when writing
> functions which operate on a Process of any type? Like e.g.
>
> 	changeDeparture :: PlaceDep -> Process -> Process
>
> I would have to pattern match against all the constructors, wouldn't I?
> If I don't have just two Processes types, but 20 of them, wouldn't that
> become messy?
>
> In the second approach I only have to match Process and I can be
> certain there is a PlaceDep to be altered.

That is the tradeoff between caring more if they are a belt/train or you
don't except in some functions which can pay the price of pattern
matching on inner constructors. If you have many functions as
changeDeparture I would go with the approach you say, but otherwise I
would go with the first just because seems clearer to me. This is a
question of "what you problem requires more" than a "always use this
option" thing.

What I can tell you is what other options you have at your disposal so
you can consider them. A common option is to provide on the module the
data type is defined the only functions that operate directly on the
constructors such that every other operation can be implemented as
composition of such functions. The classical example is FIFOs where

     pop :: FIFO a -> Maybe a
     peek :: FIFO a -> Maybe a
     push :: a -> FIFO a -> FIFO a

Would be the only functions allowed to pattern match on the constructors
for them you are sure they don't leak the underlying implementation (you
want abstraction) and they give you the semantics of the FIFO. This way
you can omit the constructors from the exports of the module and get
function that operate of all the sum branches without explicit pattern
matching.

There is other more fine alternative in GHC called ViewPatterns[1] &
PatternSynonyms[2]. The first does something like what Data.Sequence does
with their view and ViewL datatype. The second is probably more
interesting to your use case. It provides an alternative "pattern" which
you can see as an alternate constructor for both branches of your data.
So in your example you could write if you go with your last alternative
(I hope I get this right).

     pattern Train a b (TP c) = Process a b (DepartureTime c)
     pattern Belt a b (BP c)  = Process a b (Speed c)

Which let you use Train/Belt as constructor in the functions you want on
top of the usual Process constructor which you probably want to use more 
commonly.

[1]: https://ghc.haskell.org/trac/ghc/wiki/ViewPatterns
[2]: https://ghc.haskell.org/trac/ghc/wiki/PatternSynonyms


More information about the Haskell-Cafe mailing list