agentm / project-m36

Project: M36 Relational Algebra Engine
The Unlicense
876 stars 47 forks source link

Atomable for types without access to constructors #207

Open matchwood opened 6 years ago

matchwood commented 6 years ago

I am trying to store the UUID type, but I can't work out a principled way to write an Atomable instance for it.

I can convert it to a Bytestring in Atomable, and then store that, but, aside from this being somewhat inefficient, there is no pure way to convert a Bytestring back to a UUID, as it may fail to parse, and the fromAtom function does not allow for failure of any kind. Of course I can simply use error but I don't like the idea that my data can then get into a completely failing state, if somehow a bad UUID bytestring gets persisted.

matchwood commented 6 years ago

I just noticed that, in fact, pretty much all fromAtom instances use error. Is there a reason for this? Are the errors caught and handled somewhere? It looks like Either err a would be perfect here, is there any reason it wasn't used?

agentm commented 6 years ago

Hi @matchwood, I have been meaning to add a native UUID type, especially since we use them internally. A user request certainly puts the item higher in my priority list, so thanks for opening this issue.

To answer the more general question regarding type validation: we are attempting to use the Haskell scheme whereby value constructors are private and then constructor functions are exposed. Thus, a Text -> UUID function within runtime scope could return an AtomFunctionError (instead of throwing an exception) which will be returned to the user if the Text representation cannot be converted to a UUID.

In general, we try to use error as sparingly as possible when we expect the condition to never occur, but it's hard not to lean on it in Generics code. Suggestions are welcome!

This strategy in Project:M36 is not so successful yet because we don't support modules, but adding module support (with private/public export distinction) seems like the obvious solution.

What do you think?

agentm commented 6 years ago

Oh, I forgot to mention- it is possible to create data types with no visible public constructors today, but it has to be done from Haskell-land, not from within tutd (example: Interval data type). Visibility will be supported once we implement modules.

matchwood commented 6 years ago

Hi @agentm, thanks for the speedy responses!

With respect to Atomable I'm still not quite sure why fromAtom is defined as Atom -> a rather than Atom -> Either Text a - the type of Atom itself ensures that no fromAtom implementation can ever be written without using error. I'm not referring even to generics based code, but all of the instances eg https://github.com/agentm/project-m36/blob/master/src/lib/ProjectM36/Atomable.hs#L62 .

I think I can see your point about AtomFunctionError with respect to Atom functions (though I haven't explored that part of the domain yet), but I'm not sure I see it when it comes to the Atomable class itself.