-
Notifications
You must be signed in to change notification settings - Fork 359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Result instead of Maybe for List.head and the like #369
Comments
One consideration which I think is significant here is internationalization. Not that the error type should do it, but that the error type should make it easy to do. This, I think, argues against making the error type a String (e.g. "head of empty list"), because that is awkward to match for translation purposes. That is, it is brittle and inefficient to match the English string to translate to another language -- it would be better if the error were something like:
... and then one could pattern-match efficiently to translate for the GUI. In fact, even the 'base case' of an English-only app is far better off with an actual error type than a String. Consider index-out-of-bounds for
... then even in the English-only case you can construct whatever phrase for your GUI is most meaningful. (Note that the two Ints in this example would represent the requested offset and the maximum offset). I suppose that, for convenience, one could add a function like this:
... in order to provide a kind of default string representation. |
+1 for I wasn't really conceptually in favor of this until I read the idea of " Not sure how much the perf difference will matter in practice; I'd assume this wouldn't affect pattern matching, which will presumably be responsible for most list-splitting operations in practice anyway? |
Alright, added this to #322. The pattern is to close the issue so it does not count towards our "open bugs" and then continue any discussion or exploration of this here.
Next step is to measure it then. Pattern matching is the same, but you are now allocating strings (or something) for every I know that Jane Street has had issues with this. I think this is the library that does these tricks, but I cannot find the supporting docs right now. Maybe their case is a bit different? Can someone research this more thoroughly so we know its relevance here? |
BTW the documentation for filterMap presumes |
Continuing from here.
List.head
currently has typeList a -> Maybe a
, and similarlyMaybe
appears in return types of other functions likeArray.get
.Seeing the
Maybe
as signalling partiality of these functions (e.g., sometimes there is no head, so the function would fail, but instead is signalling the partiality in its return type for explicit treatment by the consumer), one wonders why notResult
is used instead. (KeepingMaybe
for characteristic uses of a data structure nature, rather than of a partial function nature. E.g., an optional value from a.json
file would still be represented as aMaybe
.)One issue with this is performance: Does it have a bad impact on performance in typical uses of the function (maybe many of them throughout some recursion in a program) if the type of
head
is changed toList a -> Result T a
for some typeT
?Another issue is what the type
T
should be. Possible options:T = String
, andList.head
returns something likeErr "head of empty list"
in the failing case,Array.get
returns something likeErr "invalid index"
orErr "lookup failed at index 17"
on failure, etc.T
is some dedicated union type which represents different failure causes. It could also be several different union types, e.g., one for errors possible on lists, one for errors possible on arrays, etc. Something like the various union types in this GHC base module.T = ()
, and the consumer becomes responsible for filling in specific "error messages" if desired. As inResult.map2 f (...) (Result.formatError (always "head of empty list") (List.head l))
.T
is chosen differently depending on what kind of additional information can meaningfully be provided in case of failure of specific functions. For example, forList.head
the typeT
would indeed be()
like in the previous point, but forArray.get
the typeT
would beInt
in order to easily give access to the index which led to the failure. One could then, analogously to above, writeResult.map2 f (...) (Result.formatError (always "something went wrong with getting") (Array.get some-expression a))
, but would also have the option of writing something likeResult.map2 f (...) (Result.formatError (\i -> "lookup at index " ++ toString i ++ " failed") (Array.get some-expression a))
.The text was updated successfully, but these errors were encountered: