[Haskell-cafe] How to write a Monad instance for this type

PICCA Frederic-Emmanuel frederic-emmanuel.picca at synchrotron-soleil.fr
Fri Sep 6 12:57:15 UTC 2019

thanks I lot for your time, I will think about this for my use cases :)


De : MarLinn [monkleyon at gmail.com]
Envoyé : vendredi 6 septembre 2019 14:51
À : PICCA Frederic-Emmanuel; haskell-cafe at haskell.org
Objet : Re: [Haskell-cafe] How to write a Monad instance for this type

So I discribe a location in the tree, like this with another type quite similar to the first but with only
one child per group. This way there is only one dataset extracted.

(maybe later, I will discuss about extracting  multiple dataset ;).

data Hdf5Path sh e
  = H5RootPath (Hdf5Path sh e)
  | H5GroupPath ByteString (Hdf5Path sh e)
  | H5DatasetPath ByteString

hdf5p $ group "name" $ group "otherName" $ dataset "myDataset"

Is there a better way to do this sort of things.

The answer to this depends a lot on how powerful you want your path to be.
But the easiest way would probably be to just wrap functions:

        -- can be used with functions from Data.List
        data Path a = GroupPath ([Hdf5M a] -> Hdf5M a) (Path a) | …

        test  = hdf5p $ group head   $ group (firstOfName "otherName") $ dataset "mydataset"
        test2 = hdf5p $ group (!! 6) $ group (firstOfName "otherName") $ dataset "mydataset"
        firstOfName n = fromJust . (find $ hasName n)
        hasName :: ByteString -> Hdf5M a -> Bool

Or if you want more restrictions on which types of paths can be constructed

        data Path a = GroupPathWithFilter (Hdf5M a -> Bool) (Path a) | GroupPathByIndex Int (Path a) …

        -- equivalent to "head"
        test  = hdf5p $ group (const True) $ group (hasName "otherName") $ dataset "mydataset"
        test2 = hdf5p $ groupAt 6 $ group (hasName "otherName") $ dataset "mydataset"

Side note: I don't see a reason why the path needs to be recursive if this is all you want.

        type Path a = [PathSegment a]
        data PathSegment a = GroupPath (Hdf5M a -> Bool) | …

        test  = hdf5p [group (const True) , group (hasName "otherName") , dataset "mydataset"]

 What if you want something more like an XPath or a path with wildcards? You can still expand on these ideas easily.

        type Path a = [PathSegment a]
        data PathSegment a = GroupPath ([Hdf5M a] -> [Hdf5M a]) | …

        test  = hdf5p [group (pure . head)   , group (filter $ hasName "otherName") , dataset "mydataset"]
        test2 = hdf5p [group (pure . (!! 6)) , group (filter $ hasName "otherName") , dataset "mydataset"]

        -- or more likely
        test  = hdf5p  [group head   , groups (hasName "otherName") , dataset "mydataset"]
        test2 = hdf5p' [group (!! 6) , groups (hasName "otherName") , dataset "mydataset"]

        -- But these are basically just lists of [Hdf5M a] → [Hdf5M a] functions with one special function
        -- at the end – which can also be cast as such a function. Therefore something like this would also be possible:
        newtype Path a = Path [[Hdf5M a] -> [Hdf5M a]]
        compilePath (Path fs) = filter isDataset . foldl1 (.) fs

        -- Path can also be turned into a monoid now
        test  = hdf5p $ group head <> groups (hasName "otherName") <> dataset "mydataset"

        -- which also means it would be prudent to reduce this to
        newtype Path a = Path ([Hdf5M a] -> [Hdf5M a])

While this final solution looks quite elegant from my POV, there are several directions this can't be extended into as easily as the recursive tree.

So this is just a bunch of options from a few minutes of brainstorming, the best option for your particular problem is probably somewhere between these and the ones you already had.


More information about the Haskell-Cafe mailing list