5 ms·
Yes, it feels great to just drop `read` into a context with enough type information to infer the return type. On the other hand, when the type context is not s
by dmytrish 9y ago
Yes, it feels great to just drop `read` into a context with enough type information to infer the return type.
On the other hand, when the type context is not sufficient, it gets a bit bulky:
-- with sufficient type context:
xs <- map read <$> lines <$> getContents
-- an ugly inline type signature:
xs <- map (read :: String -> Int) <$> lines <$> getContents
For many such calls it's good to monomorphize:
readInt :: String -> Int
readInt = read
but it still does not feel elegant (what about other return types?).
Edit: obviously, this must have been `xs <-`, not `let xs =`.
- masklinn 9y agoCouldn't you just type `xs` as `[Int]` and let the compiler work itself backwards from there?
- dmytrish 9y agoI don't know how can I actually do this inside a do-block: xs :: [Int] <- ... does not work without `ScopedTypeVariables` (and I don't like proliferation of redundant language extensions). In Rust, sure, it's not a problem and plays well with the language. My point is, it is easy to abuse this feature (this example is from Haskell Prelude!), even though it is indispensable in some situations (like `mempty :: a`).
- marcosdumay 9y agoYou can either type the return value at the end of your line: xs <- map read <$> lines <$> getContents :: IO [Int] Or you can force the xs type on some other line: let _ = xs :: Int There is a recent idiom for that last format that lets you write on the same line as the expression. I think it's something like: (xs @ [Int]) <- map read <$> lines <$> getContents But I haven't used it yet and I am not sure exactly what version of GHC allows it.
- dmytrish 9y agoToday I learned that `:: IO [Int]` at the end of an expression is applied to the whole expression. Thanks!
- thinkpad20 9y agoAlmost all Haskell code written these days uses at least a handful, if not a barrel-full, of extensions, and ScopedTypeVariables is one of the most common ones. Of course, you’re completely free to do whatever you’d like with your own code, but you’ll probably find it hard to avoid extensions — at the least many of them will be used by some libraries you’re depending on.
- tome 9y ago> does not work without `ScopedTypeVariables` (and I don't like proliferation of redundant language extensions). It does something useful for you! How can it be redundant?
- chowells 9y agoYou don't like the part where compiler authors are free to make efforts to improve the language that are clearly delineated as not part of the standard and easy to not enable if they prove to not be a good idea in practice? What are the alternatives? Completely discarding the language standard? Never making attempts to improve the language? Requiring all experiments to go through a standardization committee before real-world testing? None of those strike me as obviously better.
- dmytrish 9y agoI am definitely not against languages extensions in general. I think that it's one of the unique features of Haskell that keep it stable and flexible at the same time. If I already have `ScopedTypeVariables` in scope for other valid reasons, I am happy to use it. It's just that I'd rather not enable it for tiny cosmetic improvement like this.
- lomnakkus 9y agoIf it makes you feel any better, I suspect that ScopedTypeVariables is basically how it should have worked in the first place. (The default behavior is pretty weird/surprising.)
- erikpukinskis 9y agoIs magic worth anything if it doesn’t work on 100% of its surface? Isn’t “use magic, except in cases where the magical internals don’t apply—then be explicit” a strictly worse API than “just be explicit”?
- dmytrish 9y agoReturn type polymorphism has usecases where it is irreplaceable (see other comment threads). I am just pointing out an example of bad use, which is not a problem of the language, just of this specific API. As for APIs in general, sometimes they do need some leeway for future extension.