[Haskell-cafe] A practical Haskell puzzle

Yves Parès limestrael at gmail.com
Mon Feb 28 12:01:14 CET 2011


>  takeC :: Int -> Compoz a b -> (exists c. Compoz a c)
>  dropC :: Int -> Compoz a b -> (exists c. Compoz c b)

What does 'exists' means? To create a rank-2 type can't you use:

takeC :: Int -> Compoz a b -> (forall c. Compoz a c)

??

2011/2/28 Heinrich Apfelmus <apfelmus at quantentunnel.de>

> Yitzchak Gale wrote:
>
>> You have written a large software system in Haskell. Wishing to
>> play to Haskell's strength, you have structured your system
>> as a series of composable layers. So you have data types
>>
>> Layer1, Layer2, ...
>>
>> and functions
>>
>> layer2 :: Layer1 -> Layer2
>> layer3 :: Layer2 -> Layer3
>> ....
>>
>> etc.
>>
>> Of course you'll want to be able to run any range
>> of the layers separately, at least for testing and debugging
>> purposes if not for the functionality itself.
>>
>> So your UI module (command line or whatever) that launches
>> your application provides a data type
>>
>> data Layers = Layers Int Int
>>
>> that indicates which layers to run, and functions
>>
>> deserialize1 :: L.ByteString -> Layer1
>> deserialize2 :: L.ByteString -> Layer2
>> ....
>>
>> serialize1 :: Layer1 -> L.ByteString
>> serialize2 :: Layer2 -> L.ByteString
>> ....
>>
>> etc.
>>
>> Now you need a function
>>
>> runLayers :: Layers -> L.ByteString -> L.ByteString
>>
>> so that the effect is for example
>>
>> runLayers (Layers 4 6) = serialize6 . layer6 . layer5 . deserialize4
>>
>> [..]
>>
>>
>> What is the best way to write runLayers? Feel free to change
>> the details of the above design, as long as it meets the
>> functionality requirements expressed.
>>
>
> Solution: compose all the functions, but do not use the standard function
> composition (.) to do that. Instead, make a new data type with composition
> as constructor. This way, you can inspect the composition afterwards and run
> only parts of it.
>
> Solution, put differently: Make a type-safe list of the whole chain of
> functions. Then, the  runLayers  function throws away everything outside the
> range and composes what is left.
>
> Here a rough sketch of what I have in mind:
>
>   data Compoz a b where
>       Id   :: Compoz a a
>       Cons :: (Serialize a,b,c) => (b -> c) -> Compoz a b -> Compoz a c
>
>   -- this value needs to be written out
>   chain = layer20 `Cons` layer 19 ...
>
>   runLayers (Layer a b) =
>       deserialize . (run . takeC (b-a) . dropC a $ chain) . serialize
>
>   takeC :: Int -> Compoz a b -> (exists c. Compoz a c)
>   dropC :: Int -> Compoz a b -> (exists c. Compoz c b)
>
>   run :: Compoz a b -> (a -> b)
>
> Of course, you will have to wrestle with the existential types for takeC
>  and  dropC  a bit, but that shouldn't be much of a problem. For instance,
> you can fuse these functions into  runLayers  and hide the existential types
> somewhere in the recursion.
>
>
> Regards,
> Heinrich Apfelmus
>
> --
> http://apfelmus.nfshost.com
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20110228/23140cff/attachment.htm>


More information about the Haskell-Cafe mailing list