Live data from Hacker News

Haskell in the Large [pdf]

code.haskell.org

71–80 of 139 posts

Re: Haskell in the Large [pdf]

#71

Earlier quoted context omitted.

Haskell/Scala/etc makes it easy to nudge other developers into avoiding mistakes. A concrete example: I had a Scala system (build on Scalaz, which is a library providing Haskell for Scala), and one of our core types was DBTransaction[_] (a monad). A developer (a skeptic of the type system) was complaining to me about all the excess work he needed to go through, how he couldn't get properly construct a LazyStream[Foo]…

So if I understand correctly, the real point is instead of programming defensively at runtime, you can do it in the type system. My main question is the extent to which this is possible in more conventional languages.

Yep - that's probably a fair way to describe it. It's of course possible in other statically typed languages, it's just not as easy.

There are also some things that I'm not sure are reasonable at all in something like Java/C++ without writing a lot of code. For example: https://www.chrisstucchio.com/blog/2014/type_safe_vector_add...

Re: Haskell in the Large [pdf]

#72
post #8

Has anyone used both Haskell and OCaml (or F#?)? How do they compare in practice? I've been wanting to put some time into a functional language and I've been debating between Haskell and OCaml. Because of F#, OCaml seems like it might be the more practical language (i.e. direct job opportunities). However, excluding F#, Haskell does seem to much more popular than OCaml.

My experience is that, Haskell syntax is a dream compared to Ocaml, with 'where' clauses, beautifully simple lambda syntax, do notation support, . and $ composition, typeclass operator overloading. Ocaml is more practical in a hard to explain way. Much more predictable in terms of it's memory and cpu use with non-lazy default evaluation, and I found much better performing on general code.

Funny, I have the opposite experience. Where clauses force you to look down and then up again (bonus if you managed to use both let and where in the same function!). The lambda syntax is a matter of debate, writing "fun" instead of "\" doesn't bother me and is, IMHO, clearer. OCaml has an equivalent of $ with @@, but I haven't seen it used very much, since chaining functions with |> is so convenient.

OCaml does not have generic ways of doing monadic stuff (do notation or generic >>=), which means in practice that monadic code looks like "fun1 x >>= (fun r -> )" which is kind of awkward. It also doesn't have typeclasses (yet).

However, one thing you're unlikely to find in OCaml and which is unfortunately not uncommon in Haskell is functions with a long list of positional parameters (since you have named arguments) or different versions of the same function with a "_" suffix, depending on various defaults (since you have named arguments). It makes a tremendous difference of readability when dealing with complex code.

Also, interface files (.mli), while a bit of a pain to maintain at times, give a very clear idea of what interface a given module exposes.

All in all, I find OCaml code much easier to read, not to mention less "clever" than equivalent Haskell code.

Re: Haskell in the Large [pdf]

#73

“Make illegal states unrepresentable” Types pay off the most on large systems. Architectural requirements captured formally. This more than ANYTHING else is why I want to move enterprisey app code to Haskell. Having worked on numerous ginormous enterprisey systems -- which are usually doing pretty straightforward things, just at scale, and needing to be maintained by non-brilliant developers -- I can say pretty secur…

invariants could be lifted into the type system Is there a reason this is only possible in Haskell, or does Haskell just make it super convenient / idiomatic?

A toy example would be the following C code

    #include 
    
    double sine(double x){
      reformat_hard_drive();
      return sin(x);
    }
which can be easily translated to Haskell

    sine x = do
      reformat_hard_drive
      return (sin x)
So we can write the same stupid function in both languages. The bit that's specific to Haskell, as opposed to just any typed language, is that sine and sin have different types. sin is (Double -> Double) while sine is (Double -> IO Double), so swapping in sine for sin causes the code to fail to compile. Comparatively, you can drop in a random sine anywhere in your C code and the compiler will happily chug right along. While I've seen ways of implementing various invariant catching techniques like the Maybe type in C, I haven't seen anything that would catch the sine function.

Now, as I said, this is a toy example. The real solution would be to fire whoever wrote the sine function. However, in larger systems, it can be translated into invariants such as declaring that a function cannot access the database or send packets on the network.

Re: Haskell in the Large [pdf]

#74
post #51
post #29

Earlier quoted context omitted.

Strictness can always embed laziness---this is sometimes an argument for the natural superiority of strictness---so long as you have lightweight lambdas. Thus, in OCaml you'll see a lot of thunk () = long_computation effectively. Is that syntactic noise enough to disable the advantages of laziness? Actually, maybe!

> Strictness can always embed laziness And vice versa, although I think embedding strictness in laziness is probably more syntactically heavyweight. http://h2.jaguarpaw.co.uk/posts/strictness-in-types/ > Is that syntactic noise enough to disable the advantages of laziness? Actually, maybe! Hmm, if that's the case then it seems that thunk = return long_computation is enough to disable the advantages of monads! :)

But note that achieving the strictness type requires the use of `seq` which is perhaps, arguably, a more arbitrary language feature than function abstraction and unit are! In particular, it's been a big debate as to what the proper semantics for seq are—the dust is technically unsettled, despite the long history of seq in Haskell.

Re: Haskell in the Large [pdf]

#75

Earlier quoted context omitted.

Haskell/Scala/etc makes it easy to nudge other developers into avoiding mistakes. A concrete example: I had a Scala system (build on Scalaz, which is a library providing Haskell for Scala), and one of our core types was DBTransaction[_] (a monad). A developer (a skeptic of the type system) was complaining to me about all the excess work he needed to go through, how he couldn't get properly construct a LazyStream[Foo]…

So if I understand correctly, the real point is instead of programming defensively at runtime, you can do it in the type system. My main question is the extent to which this is possible in more conventional languages.

Just imagine that every static constraint you want to encode has to be written in the language of the types, a subset of your chosen language.

C's language of types is incredibly primitive. Haskell's is quite nice. Agda/Idris/Coq's type language is technically equivalent to its value language so you can encode incredible things.

It turns out that due to people's general desire for compilation to always terminate that the type language behaves quite different from the value language. It also turns out that the type language operates differently because we're more interested in logical constraints than actual evaluation.

The major thing that the above change is that you no longer have the "it's always a Turing complete language" excuse. Type languages can actually significantly and meaningfully differ in power.

So it's meaningful to say that there are constraints that can be encoded statically in Haskell but cannot in C (no matter how you try). And it's also true that Coq can encode constraints that cannot be encoded in Haskell (though Haskell keeps making its type language stronger!).

Re: Haskell in the Large [pdf]

#76
post #42

Earlier quoted context omitted.

A sidenote: There is nothing in Java/C++ etc that would stop one from making only legal states representable. It's just easier and more obvious in ML family...

That's only true in the most trivial Turing Tarpit sense, though. Ease of use and defaults matter in practice. E.g. you can do compile-time exhaustiveness-checked pattern matching using the visitor pattern in Java/C++, but try doing that in practice and the amount of boilerplate just becomes unbearable -- and actually obscures (rather than illuminate) the essence of the data structure. There's also the lack of higher…

Additionally, the Turing Tarpit doesn't apply in the level of the type language. These languages actually differ significantly in power since they're not Turing complete.

Thus, there are certainly non-trivial and interesting static invariants which you can encode in Haskell and cannot in Java.

The most critical and strong common one is probably parametricity.

Re: Haskell in the Large [pdf]

#77
post #55

Earlier quoted context omitted.

The modules are great in OCaml. The short variable names in Haskell follow the convention that the more polymorphic your variable is, the shorter its name should be. Eg in map f (x:xs) = f x : xs; map _ [] = [] f, x and xs are very polymorphic, so there's really no better longer name there.

First, people are not shy about using short names in general, however polymorphic the variable is. And you could easily write: map func (item:items)

The point is typically something like "generic english names don't provide much benefit over conventional short names".

When I'm writing map, parametricity literally ensures that I cannot care about the element of the list. Giving their priority with any thought toward the name is actually taking the focus off the list structure where it belongs.

Re: Haskell in the Large [pdf]

#78
post #55

Earlier quoted context omitted.

OCaml has, IMHO, strong syntactic advantages over Haskell which have a major impact on readability: - the way you access records (which also means it's not going to clutter your namespace) - named arguments - default values - not an OCaml-the-language property, but there is much less of a race in the OCaml ecosystem to write the shortest variable name possible and accumulate the most ASCII operators Also, the great m…

The modules are great in OCaml. The short variable names in Haskell follow the convention that the more polymorphic your variable is, the shorter its name should be. Eg in map f (x:xs) = f x : xs; map _ [] = [] f, x and xs are very polymorphic, so there's really no better longer name there.

    map fn (head:tail) = (fn head):(map fn tail)
    map _ [] = []

Re: Haskell in the Large [pdf]

#79
post #23

Earlier quoted context omitted.

I think "interpreter/compiler" problems arise way more frequently than people expect. It's just they're often not called that until they're being tackled by interpreter/compiler experts. In particular, you can think of things like message passing, interpreter/command patterns, and anything which uses reflection as being at least a little like an AST/interpreter pattern if you look at it in the right light. Then, if y…

I completely agree. When viewed from the right angle almost everything is a combination of some "VM bytecode" and a "compiler" targeting that bytecode. Greenspun's tenth rule applies to anything large enough. That's not what I'm getting at. What I'm getting at is that when you have a bunch of problem solvers well versed in programming language design and theory the programming language at that point is no longer rele…

I'm certain that it's impossible to separate out the PhD Effect from the Language Effect entirely. I'm also certain that the Language Effect is non-zero. I'm finally pretty confident that there's an interaction, the Language-Lets-You-Hire-PhDs-More-Easily Effect, that's in play.

I don't think PHP is an apt comparison because much of this presentation is actually honing in on very particular points of Haskell-the-language which are directly benefitting SC in practice. SC's use of Mu doesn't detract from this either---both Mu and GHC implement Haskell-the-language (to a large degree) and the core benefits they speak of are exactly those within Haskell-the-language.

Now, SC needed some extra advantages: portable code seems to be a big one as well as dramatic cross-compatibility. These are compiler features more than Haskell-the-language features and so they wrote Mu.

I think the point about Erlang is awesome. I think Haskell could learn a lot from Erlang... and frankly also improve upon its safety and readability tremendously using types. That's a personal bet.

I don't think Dialyzer is even a slightly acceptable replacement for the language advantages of Haskell, however. They are not even playing the same game.

Re: Haskell in the Large [pdf]

#80
post #52

Earlier quoted context omitted.

> So all you need are compiler/interpreter experts that can turn any problem into a interpreter/compiler problem and you're golden. Any text processing, symbolic data structure manipulation can be reduced to a compiler phase, it is just apparently many CS degrees don't teach it properly. > Alternatively, Facebook has been experimenting with Haskell and OCaml. Seeing their case studies would be valuable as well. Micro…

Microsoft as well. I don't know what kind of production systems are built with F# but maybe there are a few.

Microsoft recently released Bond, a message encoding library, which was written in Haskell.

They don't only have one modern FP iron in the fire.

Post reply on HN