Why doesn't Haskell's Prelude.read return a Maybe?
stackoverflow.com/questions/8066850/why-doesn...Posted Nov 10, 2011, 10:39 AM UTC
Posted Nov 10, 2011, 10:39 AM UTC
This is part of a general reliance on partiality by the standard library:
head, tail, init, last, (!!), div, read, the Get monad
and many more...
We have very nice tools to work with Maybe values (their standard class instances) so I don't think it would be that horrible to have all of those functions return Maybe-wrapped values.
When you can prove the value is a Just from those functions, you should be able to justify yourself via:
unjust :: String -> Maybe a -> a
Where the String is an argument that should explain the proof of why the value can't be Nothing.
When you can prove the value is a Just from those functions, you should be able to justify yourself via:
unjust :: String -> Maybe a -> a
Where the String is an argument that should explain the proof of why the value can't be Nothing.
Might I interest you in some Agda, sir?
IsJust : ∀ {A} → Maybe A → Set
IsJust nothing = ⊥
IsJust (just _) = ⊤
fromJust : ∀ {A} → (ma : Maybe A) → IsJust ma → A
fromJust nothing ()
fromJust (just x) tt = x
unjust should alse accept PersonalInfo and Address params, just in case person who will use your code is a maniac serial killer.
If your code has a bug, someone will hunt you down and kill you? That seems rather... unjust.
i believe there have been projects to develop replacement preludes, i wonder what it would take for one to get traction.
Aren't most replacement preludes quite specialised? There's either preludes containing masses of type classes for algebraic structures, or preludes where everything is a type class, etc. I'm not aware of any serious effort at an alternative, usable, general purpose prelude. Is there one?
It would be interesting to design a new prelude from the ground up.
I thought there was a least one or two such projects with a more pragmatic approach but I don't really know. Hoping someone more knowledgeable will jump in here. Maybe blog posts like this pointing out specific issues with the default prelude are just what is needed to get things going..
I'm tempted if nobody chimes in. A very conservative partiality-removal pass wouldn't be hard. Though I'd find it very hard to resist a crack at resolving map vs. fmap vs. <$> vs. mapM all ultimately being the same thing.... but then, that's what kills this process. Everyone who takes the task on wants to fix "everything wrong with Prelude", for suitably different values of "everything". Maybe what's needed is a metaproposal that it is the sense of the community that Prelude needs to be fixed up, and it is acceptable for it to be a slow process with many steps instead of one big bang that arrives at The Solution all at once. And yes, that has its own set of costs, but I can't help but notice how much of every interesting Haskell tutorial like LYAH must sit there and explain why all these silly things are in there....
Why not unsafeHead, unsafeTail, ...
Because those don't encourage the author to justify his reliance on partiality.
Partiality is a bad thing, and sometimes it is needed. When it is, it needs to be explicitly justified.
Because they're perfectly safe. They fail when they're given certain arguments, but in Haskell, unsafe functions can actually break Haskell if used improperly. Using head improperly will screw up your program if you don't catch the error, but the Haskell runtime will be fine.
Asynchronous exceptions are not “unsafe.” Partial functions simply lead to bugs which can be hard to track down, they don’t compromise the integrity of the run-time system.
I would be against watering down “unsafe.” It should be reserved for the truly scary functions.
Would upvote twice.
Haskell is designed for robustness and type safety; it's not only stupid, it's antithetical for Prelude.read to raise an error instead of returning Nothing.
When I want to know more about the result of the parse, I use
reads
So the functionality you want is available, read is just a convenience function, from my point of view.
Yes, but reads is usually inconvenient to use
as a safe version, too. We need another convenience
function for that.
This can probably be changed in future Haskell standards, but someone would need to drive the process.
Now that the library proposal process has been relaxed, the first step would be just get it into a library that is supported by GHC and other popular compilers. Once that is an established fact, it can be codified in a subsequent version of the standard.
Well, obviously, returning Maybe is too limited. We really want something more like:
read :: (Read a, Monad m) => String -> m a
read str =
case reads str of
[(a,"")] -> return a
_ -> fail $ "Failed to read " ++ str
So that we can have:
read "1" :: Maybe Int
read "1" :: Either String Int
But then we remember that 'fail' is evil and doesn't belong in Monad. What we really need is MonadFail,
http://www.haskell.org/haskellwiki/Functor_hierarchy_proposal
Though, that does not really stop us from using fail now. Except that it is evil. But maybe less evil than calling errror.
Would be nice if the above function was added to Text.Read as readM.
Not sure if anyone has proposed it yet. I have seen it defined multiple times though..
Also. In theory, there could be some types for which read never fails. So, we could still have a non-failing version of, read :: (AlwaysRead a) => String -> a. Which only contains types which can never fail to be read. But, in practice, I don't think there are many useful types like that.
Some functions used to work that way.
The consensus these days, though, is that you should return the Maybe/Either in that case, and not the polymorphic (forall m. MonadFail m => m a).
There was a long discussion about that as a subthread of dons'
proposal
to add maybeRead to the base libraries. (See also dons' post below.)
There was a lot of bikeshedding about this. But I think the upshot of
the discussion was that you really don't need all of that machinery.
Since Maybe is the universal example example of this, you actually
lose no generally by using Maybe. It is trivial
to use maybeRead with any scheme you decide to use.
So by the K.I.S.S. principle, I think that is the best way to go.
Yeah. I actually agree with that. For most of the monads that you want to use read in, you don't really get anything exciting by call 'fail' instead of just returning Nothing. Mostly you just get more to think about and more complex type errors.
See this libraries proposal from 2008: http://www.haskell.org/pipermail/libraries/2008-February/009202.html
Let's revive that proposal.
this is the kind of crap that haskell prime should have addressed. unfortunately it seems like most of what haskell prime accomplished was to codify extensions that ghc already supports.
Haskell prime is a rolling process that in the main involves the core language. There's a rolling libraries process that's been started to be developed along with it. And part of that involves plans for a libraries-centric "big bang".
really? i thought prelude was included in haskell prime because its defined in the report.
see this thread for discussion: http://haskell.1045720.n5.nabble.com/Proposal-Change-to-library-proposal-process-tp3319350p3331653.html
i saw this with full knowledge that as someone who uses haskell extensively but has never committed to ghc or the haskell platform I'm kinda part of the problem but still, i stand by my flamebait
agreed. the high level of expertise and general skill in the haskell community seems to preclude haskell prime from every making fundamental changes...most of the community is aware of the warts and has internalized the processes for coding around them. lesser coders would have thrown in the towel and demanded a global fix
Actually, making shoddy programming practices impossible or at least inconvenient is one of the central themes of Haskell.
So you think anyone who believes language warts should be globally fixed instead of relying on communal work around knowledge is a lesser coder?
#flamebait
Actually, making shoddy programming practices impossible or at least inconvenient is one of the central themes of Haskell.
inconvenient? maybe you didn't read the wiki page on how to blow your foot off with a simple fold
Naturally. That's why languages favored by "lesser programmers" like Java have ceded to popular demand and eliminated null pointers and partial functions entirely!
For similar reasons, python and ruby prevent developers from monkeypatching classes at runtime.
I wish there were a way to import a module that clashes with the prelude without having to add extra noise to every single file. The noise can be gotten down to just "import SafePrelude" if you build with -XNoImplicitPrelude, but it still seems crufty to need to always remember that (including when using ghci).
including when using ghci
http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/ghci-dot-files.html
You can use a language pragma, that way you get the extension when compiling and when in ghci:
{-# LANGUAGE NoImplicitPrelude #-}
The Network.CGI.Protocol module has a maybeRead function.
I was wondering about something else in Prelude:
Why getLine but readLn instead of readLine, for consistency?
[deleted]
What about
div?What's wrong with
div?That's not a problem with div, it's a problem with math, although it does technically make
diva partial function. I'd argue that the proper behavior is to do that and not to makedivreturn aMaybe Int, though.