Fantasy World OCaml (2013)
chaudhuri.info
chaudhuri.info
Erlang-style actors or lightweight processes would be my dream multicore scenario (no more monads for concurrent IO!), but that's likely too difficult to graft onto the current runtime, which is otherwise extremely well-done.
Also, I'd really like checked exceptions. The omission of checked exceptions has always struck me as strange, given the emphasis on compile-time checking. Considering how fast exceptions are in OCaml, it seems like a bit of a missed opportunity -- it is faster to use exceptions for control flow [2] than matching on variants (such as Option), which usually involve an extra allocation + dereference, IIRC.
[1] http://www.ocamlpro.com/pub/multi-runtime.pdf.tar.gz
[2] Odd as it may sound, it's encouraged to use exceptions as a control-flow construct in OCaml, but that is falling out of favor in modern code as far as I can tell.
Now it may be a good idea to have an optional tool for checking exceptions -- in fact, one exists already, but I can't recall the name of it. But please don't make this mandatory unless you avoid the mistakes of Java.
Why? I absolutely hate C++ codebases where all of a sudden you get yet another type of exception that was not documented, possibly because the exception was thrown ten functions down (up) the stack.
In Java, at the very least you know what to expect and can prepare for it. Unfortunately, even there people try to avoid exceptions by throwing classes that derive from RuntimeException.
Given that Java has no sum types, checked exceptions are really the next best thing.
Here's an interesting page discussing the current effort to develop a multicore runtime: https://github.com/ocamllabs/compiler-hacking/wiki/Multicore...
1.http://projects.camlcity.org/projects/dl/ocamlnet-3.3.0test1...
2.http://www.dicosmo.org/code/parmap/
The duplicate argument thing already generates a warning (I wish warnings were enabled by default though):
# let f x x = x;;
Warning 27: unused variable x.
val f : 'a -> 'b -> 'b = <fun>
"Values of type string and bytestring are not mutable." In 4.02, strings can be made immutable (it's optional currently, to avoid breaking existing code).Camlp4 is already on the way out, being replaced by Extension Points.
Rather than adding checked exceptions, I'd rather just see more use of variants in the standard library (3rd-party libraries mainly do this already). I don't see why checked exceptions should be faster - maybe this is just a compiler optimisation problem?
Still, I enjoyed reading the post, and it is good to see people looking to improve OCaml and make suggestions.
Probably the two biggest problems, both of which are currently being worked on, is a solution to true modules/modular dependencies (which is highly beneficial to fixing the community problem of cabal hell) and a solution to the "record problem" which is probably going to come in a new GHC extension which automatically allows for structural subtyping on public records via row types.
I'm looking forward to this. I have Haskell code in production and would greatly appreciate these features. Is there a url where I can check/follow for the state of these efforts? Who is working on these? Thanks in advance.
And here's overloaded record syntax: http://www.well-typed.com/blog/84/
[0]http://ezyang.com/ [1]http://plv.mpi-sws.org/backpack/ [2]http://blog.ezyang.com/2014/07/type-classes-confluence-coher...
Completely agreed on the difference between language issues and community issues. From my perspective, the Haskell community does great with language issues. With GHC 7.10 we'll have AMP and OverloadedRecordFields, and I've seen a ton of work go into getting GHC ready for something like Backpack (throughout this summer). I think eventually these things will be solidified into a Haskell2018 or something, at which point a lot of the issues with Haskell-the-language that I've encountered when writing industry-style code will be gone. And I think that's great, and points to a bright future for Haskell; I don't think any other language has ever made me excited by the pace of progress in the language itself. (Some may say that in other languages you don't need to be excited by the next compiler release because the current one is good enough, but all languages have warts and deficiencies -- I think the GHC devs and the Haskell community do a great job finding these and trying to find clever and principled ways of improving them. See OverloadedRecordFields.)
However, I think community questions like the pipes libraries , cabal hell (to a lesser extent -- I think this is partially a tech problem that Backpack-like modules will solve), problems with the Prelude, etc, are an even bigger issue. Sadly, I think those issues are actually much harder. For instance, in the Haskell community, we constantly have issues with Strings being the default datatype for text, because Strings are just [Char]. This is a pretty terrible model for text most of the time (not all of the time, but most of the time). However, changing this requires not only changing the base library, but also hundreds of other libraries on Hackage. Some of these are likely unmaintained, and would break and stay broken. There are many ways in which I think the Haskell Prelude could be fixed (String -> Text conversion, fmap -> map and mappend -> ++ renaming, getting rid of confusing Control.* and Data.* heirarchies, etc), but the undertaking is gargantuan, because any of these changes would affect hundreds of libraries (some now unmaintained) in the ecosystem. And because of this, I've seen no plans or proposals on how Haskell should handle these sorts of changes.
Fixing Prelude is just one of the more difficult "community questions". We have a proliferation of very similar but competing libraries, which in some ways is good (people have choice, different libraries can make different design decisions, etc), but in some ways is bad (if I write a library that does streaming, I have to make a pipes version and a conduit version, or choose one). Again, Backpack modules will help here. Same goes for Haskell-to-Javascript compilers. However, with many of these, I think time will tell -- we have multiple options that are constantly evolving because we haven't really figured out the "right" way to do things yet, and eventually things will settle down.
As always, some of the hardest problems in programming are not actually coding problems, but people problems. Hopefully we can find a way going forward to find solutions to those as well.
String choice is a particular point for me. I think it's great that we have three string types as they each have their own tradeoffs. That said, I don't think the particular choice of Stringy type made is often driven by the tradeoffs as much as by convenience or partial information.
I really think it often does boil down to the Prelude design. Solving the momentum issues there is a huge problem.
fun () ->
if foo then return r;
more code ...
is the equivalent of: fun () ->
if foo then r
else more code ...
Note that type safety would obviously have to be preserved. The returned type would have to match the return type of the overall function. {-# LANGUAGE DeriveFunctor #-}
module Return where
import Control.Monad
newtype Cont r a = Cont { runCont :: (a -> r) -> r } deriving Functor
instance Monad (Cont r) where
return a = Cont (\k -> k a)
m >>= f = Cont (\k -> runCont m (\a -> runCont (f a) k))
early :: r -> Cont r a
early a = Cont (\_ -> a)
ex :: Cont Integer [Integer]
ex = do
forM [1..] $ \i -> do
when (i == 33) (early i)
return i if some_error_condition then
None
else (
// everything else in the function is nested
)
which would be replaced with: if some_error_condition then
return None;
// everything else is not nested
The situation is particularly bad when you have to do a lot of small tests at the beginning of your function. Think permissions checks: let user_id =
match user with Some id -> id
| None ->
printf "you need to specify a user\n";
return None in
if not (permitted user_id) then
printf "this user is not permitted\n";
return None;
// go ahead and return Some object
The alternative is to use exceptions, either hidden within the function (requiring a nested function), or demanding that the caller is careful about catching exceptions. Exceptions are an unsafe back door, when what's really needed is a return statement. if some_error_condition then
None
else (
// everything else in the function is nested
)
Why not use a Maybe/Either monad like: x <- some_maybe_value
// everything else in the function isn't nested, and "x" is available (if some_maybe_value was Just)
Kind of like exceptions, but a bit more explicit. match user with
| None -> printf "you need to specify a user\n"; None
| Some user_id when not (permitted user_id) ->
printf "this user is not permitted\n"; None
| Some user_id ->
// go ahead and return Some objectIt may not be wise to break current behaviour of the char and string types, but their literals should at least support unicode escapes. One way to do this would be to bring in UCS-4/UTF-32 strings as offered by Camomile, and have some simple convention to allow UCS-4 strings to be mapped from what are UTF-8 literals in the code.
One reason is that it's very hard to get it right -- see how complex Perl 5 is which is about the only language that does do the right thing. Another reason is that baking an incorrect Unicode into the language would be worse than the current situation. For examples of brokenness, see: all of Win32, Java, Ruby.
It would be good to remove the broken String.lowercase and String.uppercase functions from the stdlib though.
Edit: Although perhaps your problem was more to do with supporting arbitrary binary in the source files (which instead are encoded as ISO-8859-1). That would be something to fix.