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

MarLinn monkleyon at gmail.com
Fri Sep 6 12:51:09 UTC 2019

> 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.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20190906/1aa307b5/attachment.html>

More information about the Haskell-Cafe mailing list