7 ms·
If ReasonML is able to form a real community, I have high hopes for its long-term prospects. Such an enjoyable language to use! I think their general approach o
by kcorbitt 9y ago
If ReasonML is able to form a real community, I have high hopes for its long-term prospects. Such an enjoyable language to use! I think their general approach of bootstrapping a community by lowering impedance with the JS ecosystem is a decent one.
In case anyone on the OCaml team is reading this though, there are two language-level changes that I think could do wonders for wider adoption. The first is modular implicits: it feels so kludgy to have to type `a + b` for integers, `a +. b` for floats and `a ^ b` for string concatenation. I know it sounds like a small thing, but it makes the language feel inelegant, and aesthetics are important. The second is a good concurrency story, ideally one that is compatible with JS-style async/await keywords for easy interop.
I know those are both being worked on; I just hope they become available in time to coincide with the wave of interest in ReasonML!
- k__ 9y agoI think the problem isn't that + +. and ^ look different, it's that they are symbols. That's also what makes scala so unapproachable, you get stuff like ++> or =*= that doesn't make any sense. x + y makes sense to most people x ^ y not so much
- s4vi0r 9y agoDo you write Scala, or have you even looked at Scala code any time in the past few years? I'm curious where this habit of spreading FUD over Scala being operator heavy came from. Maybe it was back when it first started reaching the HN front-page or something? Scala is a super approachable language, without any (that I can think of) strange operators in the stdlib. You could make a case for Cats, I guess, but writing purely functional Scala isn't necessary at all, and is something you can approach when or if you feel comfortable to do so.
- k__ 9y agoLast time I used Scala was 2010 or something. I never was a fan of the JVM stuff and Scala seemed like a reasonable alternative to Java, but I never got it.
- KirinDave 9y agohttps://github.com/scalaz/scalaz/blob/series/7.3.x/tests/src/test/scala/scalaz/BitraverseTest.scala#L41-L45 https://github.com/scalaz/scalaz/blob/series/7.3.x/tests/src... It is a mystery.
- pimeys 9y agoI'm not the biggest fan of Scala, but for me it's more that it reminds me of Java than the functional constructs. But pointing at Scalaz is a bit ridiculous. It's a known test library for trying things out and basically not allowed in any Scala codebase I've been working on.
- KirinDave 9y agoScalaz is widely used and widely panned. Even though I'm a haskell and purescript programmer that prefers to write <$> and >>=, I find Scala's approach frustrating and hard to read. Especially as type lambdas stack up. I'm just saying; the impression exists for a reason and the reason is a popular and well-known library.
- pimeys 9y agoI'm all with you here. I prefer Haskell and OCaml every time over Scala.
- renox 9y agoBut addition != concatenation, that said I prefer ~ for concatenation operator (as in D)
- StreamBright 9y agoI think the exact opposite. Finally a language where floats and integers cannot be mixed together accidentally.
- kcorbitt 9y agoThe type checker is capable of disallowing `float + int` while still allowing `int + int` and `float + float`, which is what I want.
- renox 9y agoWhy? As long as float -> int implicit conversion are forbidden, I don't see any issue with allowing implicit int -> float conversion.
- masklinn 9y agoHaskell does not allow accidentally mixing floats and integers together. In fact it doesn't even allow mixing finite and infinite-precision integers together, despite using the same operator for all number additions: Prelude> (3::Int) + (4::Integer) <interactive>:2:13: Couldn't match expected type ‘Int’ with actual type ‘Integer’ In the second argument of ‘(+)’, namely ‘(4 :: Integer)’ In the expression: (3 :: Int) + (4 :: Integer) In an equation for ‘it’: it = (3 :: Int) + (4 :: Integer) It's not by any means the only language with that property either.
- runeks 9y agoOff topic: why on earth does ghci print out that last “In an equation for ‘it’: it = […]” statement? Seems like something internal to ghci, and not something that’s relevant to the user.
- masklinn 9y agoYou'd have to check ghci's source itself, but I expect it just hands the bits over to GHC for evaluation and the relevant GHC API (sensibly) requires a name, for which ghci provides "it".
- jordwest 9y agoYou might like to try Fable and F#. I’ve been looking at it since playing with Reason and Bucklescript, and so far I’ve found Fable much easier to use and more featureful. The syntax is essentially the same as OCaml, plus it’s whitespace aware. F# has implicit `+` for basic types (though it’s not quite modular implicits). It also has a really nice syntax for async computations, similar to `async/await`. JS interop is much easier too. It can also run on the server with .NET core if you don’t want to use node. The output JS is slighter heavier and less optimised than Reason/Bucklescript, and compile times slighter slower, but at the moment those are trade offs I’m happy to make
- nozzlegear 9y agoI'll second the recommendation for F# and Fable. I'm currently working on my first project with it, where both the client and the server run F# and can share code/types. I haven't been this happy with a stack in a long while. My one complaint is how... salty some members of the F# community can be, mostly regarding the rest of the Microsoft-backed .NET ecosystem.
- raphinou 9y agoI would be interested to know how you share code between client and server. Can you share info/code? Having one code base like with ocsigen would be even better. Anything like that available?
- bad_user 9y agoThe "+" in F# is really awkward because it tries catering to both the ML type system it got and to the .NET type system underneath, inherited from C#. This is a problem because when type inference kicks in for plain functions, usage of that "+" will make the compiler assume "int". But worse, "+" in C# is not a method, but a static method and the compiler basically does magic, because you don't have this behavior for plain static methods and you don't have a generic interface in the language for "+", there's no Number, no Monoid and static methods themselves in C# can't be polymorphic. The whole notion of "static methods" is broken btw and have nothing to do with OOP. The only purpose of static methods is to enforce visibility rules and this made some sense in C++, where you could have functions living outside of classes, but even there the real problem is the lack of useful namespacing. And F# inherited this behavior, F# inherited static methods, along with math operators described as static methods. So in order to abstract over things that have "+", which is really needed in F# otherwise you can't express really basic things for an FP language like "List.sum", you have to (1) use inline functions, which aren't translated directly to .NET functions and (2) use a really awkward signature that instructs the type system that the type has a "+" static method that it can use, e.g... > let sum x y = x + y;; val sum : x:int -> y:int -> int > let inline sum x y = x + y;; val inline sum : x: ^a -> y: ^b -> ^c when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c) So this signature is really interesting — the type system is saying that our "sum" needs either an A type or a B type and one of them should have a static "+" defined, doesn't matter which one. This is close to how type classes work in other languages, however for the F# compiler this is magic that doesn't scale and making use of "static methods", a flawed concept, a signature that can't be encoded in .NET's type system and therefore the function is forced to be "inline". Which is another problem, because in F# inline functions are more like macros, or in other words these "inline" functions are not values. As soon you try using one as a value, it gets materialized and you loose the type info. So it is very ephemeral. Given this, frankly, I would rather have OCaml's operators. At least they are plain functions.
- overtowed 9y agoI'm a JS developer who tried to adopt Reason for a full stack side project in September. There is so much to love about the language and ecosystem. After about a week I decided to start over in TypeScript for a single reason: the awkward interop with promises compared to async/await, which is now available in evergreen browsers and Node 8 without compiling down. I'll definitely try again once this is ready.
- k__ 9y agoNice! I tried it with React-Native but found it a bit cumbersome to get it to interact with existing components in Reasons JSX
- KirinDave 9y agoThere's some pretty fundamental reasons that ocaml does not support open classes/modular implicits in that fashion. Essentially you want Haskell's numeric tower, and while it's pretty amazing it's worth noting that it requires a lot of machinery with big implications.
- kbenson 9y ago> The first is modular implicits: it feels so kludgy to have to type `a + b` for integers, `a +. b` for floats and `a ^ b` for string concatenation. I know it sounds like a small thing, but it makes the language feel inelegant, and aesthetics are important. That's interesting, as being forced to use the same operator for addition and for concatenation (and what's more with the result of mixed types if allowed often dependent on the order of the parameters) has always seemed extremely inelegant to me. Addition and concatenation are not the same thing. Why they should share a symbol when they don't share some properties integral to their nature (it's non-commutative) is beyond me, and I think it's caused a lot of bugs that didn't need to happen. Not allowing the addition of floats and ints together is less of a fundamental issue, but it also helps quite a few problems. Al alternative solution, if you didn't want to reply on implicit coercion would be to explicitly convert one operand to the appropriate type so they match. Or you can go whole hog and provide an entirely separate set of operators for different types, like Perl did (string concatenation is '.', and equivalents comparitors are eq,ne,gt,lt,ge,le). That works well in Perl's case, but that's mostly because for Scalars Perl really just wants to know whether you are treating it as a number or a string, so there's only two types to account for.
- baddox 9y agoCouldn’t the type system still allow using the + operator, but requiring the values on both sides to have the same type? You could do more magic like having int + float return a float, but I’d even prefer typing “int.toFloat + float” than “int +. float”.
- kbenson 9y agoYeah, that's what I was referring to by explicitly converting one operand so they are like types. I too would prefer this in a language that takes typing of this sort seriously.
- masklinn 9y ago> Couldn’t the type system still allow using the + operator, but requiring the values on both sides to have the same type? 'course it could, multiple languages already do that e.g. Rust (https://play.rust-lang.org/?gist=530fa94d3f451e896ac0d3ddeaf66ab1&version=stable https://play.rust-lang.org/?gist=530fa94d3f451e896ac0d3ddeaf...), Haskell (https://repl.it/repls/FrozenBlondUmbrellabird https://repl.it/repls/FrozenBlondUmbrellabird), Swift (https://repl.it/repls/LuckyNaiveBream https://repl.it/repls/LuckyNaiveBream)
- bjz_ 9y ago> The second is a good concurrency story, ideally one that is compatible with JS-style async/await keywords for easy interop Algebraic effects are also in the works which will help with stuff like async/await, but works over arbitrary effects (not just async). Like monads but nicely composable without the ickiness of MTL. Alas it's still unclear what the ETA is. :( Something I'm really looking forward to! https://www.reddit.com/r/ocaml/comments/63hgid/tracking_multicore_progress/ https://www.reddit.com/r/ocaml/comments/63hgid/tracking_mult...
- jwatte 9y ago> I know it sounds like a small thing, I think the case is obvious for integer vs floats -- addition should be addition. Many languages don't use "+" for string addition, because string addition is not commutative (a+b != b+a) SQL, for example, uses "||" for this, and Haskell uses "++" That being said, argument type overloading is important for clarity. One of the famous failures in Haskell is "map" only works on lists, and "fmap" on other functors.