[HN Gopher] Is Haskell a good choice for software security?
       ___________________________________________________________________
        
       Is Haskell a good choice for software security?
        
       Author : kate_galkina
       Score  : 34 points
       Date   : 2021-12-17 12:20 UTC (10 hours ago)
        
 (HTM) web link (typeable.io)
 (TXT) w3m dump (typeable.io)
        
       | mattwilsonn888 wrote:
       | Good post.
        
       | royjacobs wrote:
       | It's unfortunate that this article is based on some flawed
       | assumptions, such as "Java provided a suberbly user-friendly way
       | of serializing any object to disk and recovering it back in its
       | original form. The only unfortunate problem was that there was no
       | way to say which object you are expecting!".
       | 
       | Java serialization is not what is used by web frameworks. They
       | use JSON deserializing, typically using libraries like Jackson,
       | which are of course fully strongly typed.
        
         | marcosdumay wrote:
         | Java serialization is not used anymore because it caused plenty
         | of security issues at the beginning. That doesn't make the
         | article any wrong or misleading.
        
           | royjacobs wrote:
           | It seems rather disingenuous to talk about severely outdated
           | features without mentioning the fact that said practices are
           | multiple decades out of date.
           | 
           | Let me put it another way, it doesn't strike me as the best
           | possible example to use.
        
             | marcosdumay wrote:
             | > A similar issue has occurred with Java
             | 
             | This is clearly on the past, as an example that once
             | existed.
             | 
             | > Java provided ... there was no way
             | 
             | If anything, that text in misleading people into believing
             | that Java doesn't do it anymore, instead of just nobody
             | using it.
        
         | thrower123 wrote:
         | That's a rather common failure to understand the relevant blub
         | details that happens a lot when functional advocates draw up
         | strawmen to denigrate mainstream boring languages.
        
       | choeger wrote:
       | I have the feeling that Haskell has one feature that could be
       | super useful for security.
       | 
       | That feature is the explicit typing of effects via monads. Just
       | look at the recent log4j example: If effects were explicitly
       | typed in Java, you would potentially scratch your head why you
       | need a network monad or a "insert code into the process" effect
       | to just log a line.
       | 
       | Of course, in current Haskell, everything is put into the same IO
       | monad. But in principle, I think that effect systems could have a
       | very nice effect on software security.
        
         | lelanthran wrote:
         | > I have the feeling that Haskell has one feature that could be
         | super useful for security.
         | 
         | >
         | 
         | > That feature is the explicit typing of effects via monads.
         | Just look at the recent log4j example: If effects were
         | explicitly typed in Java, you would potentially scratch your
         | head why you need a network monad or a "insert code into the
         | process" effect to just log a line.
         | 
         | That would not have helped - the network access with RCE was a
         | _feature_ put into the library. What does the language
         | selection have to do with a feature request of _" We want
         | evaluated log strings to be able to do network access with
         | RCE"_?
         | 
         | There's nothing special in any language (even Haskell) that
         | will prevent this sort of thing.
        
           | Buttons840 wrote:
           | > What does the language selection have to do with a feature
           | request of
           | 
           | Only functions with certain type signatures can do IO in
           | Haskell. This could be broken down to be more granular such
           | that the type system makes it clear (and even somewhat of a
           | burden) to the caller whether writing to disk happens, or
           | network access, or both.
           | 
           | Imagine the entry point to your program is given all
           | "Effects", and then must pass them down the call stack as
           | needed to other functions. Without the appropriate Effect, a
           | function cannot perform the Effect. People might wonder why
           | they were required to pass the NetworkAccess Effect into
           | their logging calls.
        
             | stonemetal12 wrote:
             | Let's just hope there is a "load and execute random code
             | from the network" effect that you could disable.
             | 
             | NetworkAccess Effect wouldn't be that strange for a logging
             | system that supports multiple networked log managers like
             | syslog.
        
               | Quekid5 wrote:
               | The point isn't so much that you can _disable_ effects.
               | It 's that you literally have _no_ effects /capabilities
               | unless specifically granted.
               | 
               | That said, I'm a bit skeptical that Haskell would have
               | prevented this particular issue _in practice_. The
               | logging monad would just likely just have been called a
               | LoggingM (in MTL style) and most users would have been
               | oblivious as to exactly what it was doing... and as you
               | say: Logging to a remote system needs the network.
               | 
               | I guess what could have saved a Haskell program here is
               | that there's no such thing as "download code and execute
               | it with the same privileges as you" with being _very_
               | explicit about that. (E.g. calling  'system' or whatever)
        
               | Akronymus wrote:
               | You could split it up into 2 functions I guess. A pure
               | one that creates the log entry, then an IO one that
               | actually saves it.
        
               | Quekid5 wrote:
               | Yes, but if the IO one does <shenanigans> then you're as
               | well off. Which is... not very.
               | 
               | EDIT: Just to say: I don't mean to be flippant.
        
               | thesz wrote:
               | Accesses can be distinguished too - read and write
               | accesses are different. You can see this in [1] - there
               | are Reader and Writer monads, where Reader is used for
               | effectively unchangeable parameter to a monadic context
               | (for example, socket) and Writer is used, among other
               | things, for logging!
        
           | griffinmb wrote:
           | The point is that with a powerful Effects system, devs
           | calling the logger would have to account for the network call
           | in their own code. Someone might have wondered why that was
           | needed and gotten this addressed before it was ever
           | widespread.
        
             | lelanthran wrote:
             | > The point is that with a powerful Effects system, devs
             | calling the logger would have to account for the network
             | call in their own code. Someone might have wondered why
             | that was needed and gotten this addressed before it was
             | ever widespread.
             | 
             | No one would have wondered anything - it's a networked
             | logger, with network functionality.
        
           | lrem wrote:
           | Well, it wouldn't prevent that one user who requested the
           | feature. But other users would be made aware that their
           | logging facility now does surprising new things.
        
           | light_hue_1 wrote:
           | Haskell could and would absolutely prevent this problem.
           | 
           | Haskell does not work by aggregating together the features
           | that a whole system needs. It works by breaking down
           | permissions per function. You would immediately see that a
           | function which was only ever meant to do context lookups also
           | has network access. This would be such a crazy type for such
           | a simple function that no one would write it this way.
           | 
           | Don't think about it as aggregating effects, think about it
           | as, all of the leaves of the system have the most narrow
           | permissions possible. And that's where most bugs are, in the
           | leaves.
        
             | lelanthran wrote:
             | > You would immediately see that a function which was only
             | ever meant to do context lookups also has network access.
             | 
             | I still don't see how that would help - this logging
             | library was _SUPPOSED_ to have network access. Would a user
             | pause to wonder what the network access is for when it 's
             | literally part of the featurelist?
        
               | light_hue_1 wrote:
               | Because in Haskell, you don't give the library
               | permissions. It doesn't matter if the library had
               | permissions to do something. The library is not an
               | entity.
               | 
               | You give functions permissions on a fine-grained basis,
               | permissions which are automatically derived. The specific
               | function which has the bug didn't need network access. It
               | just needed to look something up in the environment. That
               | function would never have a type that gave it network
               | access, that would be insane and a type error.
        
               | lelanthran wrote:
               | > The specific function which has the bug didn't need
               | network access.
               | 
               | My reading of the bug and exploit is that the specific
               | function not only needed network access, it was a
               | intentional feature.
               | 
               | > It just needed to look something up in the environment.
               | 
               | That's not how I understand it - it parses the user-
               | supplied input, and fetches (and subsequently executes)
               | the package in the user-supplied input. The environment
               | is irrelevant.
               | 
               | Now, bearing in mind that this was _intentionally_ put
               | in, and that the feature is working as intended and
               | expected, how would a different programming language
               | help?
               | 
               | Even if written in (for example) Haskell, the behaviour
               | will be coded the same way, because that is the intended
               | behaviour.
        
             | MichaelBurge wrote:
             | If I were writing Haskell logging functions, I would use
             | the type "String -> IO ()" and it could do whatever it
             | wanted including network access.
             | 
             | I might distinguish                   resolveFormatString
             | :: String -> [List Parameter] -> IO String"
             | resolveFormatStringSafe :: String -> [List Parameter] ->
             | String
             | 
             | but it wouldn't be "most narrow permissions possible". It
             | would be "everything or nothing".
        
               | thesz wrote:
               | And you should use the type "Log m => String -> m ()"
               | instead of general IO.
               | 
               | This way, for one example, you can log in some State-
               | derived monad, keeping logs for caller to extract and
               | use. It is as safe as pure function. And, of course, it
               | is trivial to implement in IO.
        
               | light_hue_1 wrote:
               | You would never spot this the edge of the logging API. In
               | any case, it's easy to see this can't be the right mental
               | model for security in Haskell. main is `IO Int` so at a
               | gross level you can't say anything about an API or a
               | program. Security in Haskell is about internal
               | guarantees.
               | 
               | The developers of the library would immediately spot that
               | their call does a lot more than it was ever supposed to
               | locally. They would have a function that has a crazy
               | permissive type like IO instead of something very narrow
               | related to the specific functionality they need to do
               | their one lookup.
        
         | griffinmb wrote:
         | Effects can definitely help, but a strong type system allows
         | you to encode security concerns for compile time feedback as
         | well.
         | 
         | See https://gmb.is/refinement-types.html for a non-Haskell
         | example.
        
           | Quekid5 wrote:
           | For a much simpler example: newtypes can make enforcing
           | proper escaping[0] completely trivial and checked by the
           | compiler. It's very similar to tainted values in Perl except
           | enforced at compile time.
           | 
           | [0] No, not sanitization!
        
         | marcosdumay wrote:
         | The log4j thing was a feature very specific to the Java
         | culture. It very likely wouldn't happen in Haskell, but
         | probably wouldn't happen in Python or C either.
         | 
         | In Haskell, effectful text parsing is severely frowned upon, so
         | that template language wouldn't get used there. In Python
         | people would frown upon the multi-use function that runs a
         | template engine and logs text when those should be 2 functions.
         | In C people would be up in arms over a logging framework that
         | doesn't log exactly the text you gave it.
        
       | eternalban wrote:
       | > A similar issue has occurred with Java (and other languages,
       | see https://frohoff.github.io/appseccali-marshalling-pickles/).
       | Java provided a suberbly user-friendly way of serializing any
       | object to disk and recovering it back in its original form. The
       | only unfortunate problem was that there was no way to say which
       | object you are expecting! This allows attackers to send you
       | objects that, upon deserialization in your program, become
       | nasties that wreak havoc and steal data.
       | 
       | Not correct. You can certainly inspect before instantiation:
       | 
       | https://docs.oracle.com/javase/7/docs/platform/serialization...
        
       | jksmith wrote:
       | A companion question is the economic view. Is this research that
       | won't be applied? Otherwise, the choice is not too good for
       | anything if it takes too long to be delivered.
        
       | turminal wrote:
       | I like functional programming, but the way Haskell or Ocaml are
       | built makes it really hard to consider them seriously for
       | anything but research and/or fooling around.
        
         | Zababa wrote:
         | OCaml is used for Frama-C (static analysis of C), Coq (a proof
         | assistant), Pyre (Python typechecker), Hack (Typed PHP), Mirage
         | (Unikernel, used by Docker for Widnows and Mac), Flow
         | (Javascript typechecker), semgrep. All of these are serious.
        
         | bidirectional wrote:
         | I don't see how this isn't just patently false. Haskell is used
         | to process every single user interaction on Facebook and OCaml
         | handles billions of dollars of trades daily at Jane St. I doubt
         | your use cases are more 'serious' than that.
        
           | turminal wrote:
           | I don't think "$bigcorp uses $technology" necessarily means
           | said technology is serious and reliable. It can also mean
           | they just have a big enough dedicated team to adapt it well
           | to their use case.
           | 
           | Facebook uses btrfs in production and I'm sure it works great
           | for them, but that doesn't mean btrfs is a good fs.
           | 
           | And Jane Street has basically built their own stdlib for
           | Ocaml, didn't they?
        
           | spekcular wrote:
           | > Haskell is used to process every single user interaction on
           | Facebook
           | 
           | Do you have a citation for this? I'd love to read more.
        
             | bidirectional wrote:
             | https://engineering.fb.com/2015/06/26/security/fighting-
             | spam...
             | 
             | Every interaction is processed by a Haskell rule engine to
             | check for spam.
        
               | spekcular wrote:
               | Thanks, that's a good read.
        
         | 1-more wrote:
         | > the way Haskell or Ocaml are built
         | 
         | be specific
        
           | turminal wrote:
           | They both have a single relevant implementation and for
           | haskell in particular it's a complex behemoth. Haskell has a
           | specification in theory but a sea of extensions exists. Ocaml
           | does not have a specification. Ocaml lacks good docs and is
           | moving too fast. But the most significant thing in my opinion
           | is the community, which is heavily research oriented.
           | 
           | And that's fine, we need research languages and I'll gladly
           | continue to write software in Ocaml, but I wouldn't want to
           | pick it for a project I'd want to be well engineered.
        
             | Zababa wrote:
             | I don't think a single relevant implementation is a
             | problem, especially when therer are not a lot of people
             | working on these languages. I'm also surprised that you
             | think OCaml is moving too fast. The multicore took a lot of
             | time to have a proper design and backwards compatibiltiy,
             | and old code compiles really well.
        
             | porcoda wrote:
             | Odd. I've worked on a couple different teams over the last
             | decade that chose Ocaml precisely because we felt it was
             | the best choice to create a well engineered solution for
             | production use. Plus, Ocaml was viewed as pretty stable
             | because it's _not_ a super fast evolving language (just
             | look at how long multicore support has been  "coming
             | soon"). The docs are not as thorough as some other
             | languages, but no more painful to deal with than the
             | Doxygen docs I have to sift through for some large
             | C++-based projects.
             | 
             | Haskell I agree on - that is a fast moving language largely
             | because Haskell today is really just whatever GHC
             | implements, extensions and all. The current implementation
             | doesn't have a specification: this even came up recently on
             | a Haskell mailing list where people basically said that the
             | GHC implementation is it for the definition of the language
             | [1]. This is why the projects I mentioned above chose Ocaml
             | - in one case, we moved OFF of Haskell since the churn in
             | the community and abandonment of standardization efforts
             | around 2010 meant it was a liability for long term
             | maintainability.
             | 
             | The biggest choice we had to make was Ocaml vs an SML
             | implementation (e.g., PolyML or mlton). SML has the
             | advantage of having a formal specification, but the tooling
             | is lacking when compared to Ocaml. Ocaml was a nice
             | compromise, and we haven't really regretted it.
             | 
             | [1] https://mail.haskell.org/pipermail/haskell-
             | prime/2021-Novemb...
        
         | the_af wrote:
         | Do you mean it makes it really hard for _you_ or in general?
         | 
         | If in general... do you know about Jane Street? From Wikipedia:
         | 
         | > Jane Street [...] adopted OCaml as its main programming
         | language early on because the language's functional programming
         | style and clear expressiveness made it possible for code
         | reviews to be performed by traders who were not programmers, to
         | verify that high-performance code would do what it was intended
         | to do. [...] "OCaml helps us to quickly adapt to changing
         | market conditions, and go from prototypes to production systems
         | with less effort"
         | 
         | Doesn't seem like either research or fooling around to me!
         | Those sound like actual, pragmatic, business-related benefits!
        
           | turminal wrote:
           | > Do you mean it makes it really hard for you or in general?
           | 
           | I don't think I'm exactly alone, but there's definitely lots
           | of people that would disagree.
           | 
           | I know about Jane Street and I admire they manage to do so,
           | but I also think lots of security issues occur because the
           | language/system/library/framework in use is not well
           | understood and Ocaml makes that particularly hard in my
           | opinion. And I'm not talking about the "functional
           | programming is hard" problem, because I don't find it harder
           | than other paradigms I tried. I'm talking about the quality
           | of the docs and the speed with which the language evolves.
        
             | the_af wrote:
             | Re: the docs, I find your assertion puzzling, or at least,
             | incompatible with this quote:
             | 
             | > _[OCaml 's] clear expressiveness made it possible for
             | code reviews to be performed [at Jane Street] by traders
             | who were not programmers_
             | 
             | If OCaml was a mess, difficult to understand, or had
             | terrible docs, what the quote describes just wouldn't be
             | possible. Non-programmers doing code reviews! What could be
             | more pragmatic than that?
        
       | spekcular wrote:
       | Is this argument here just that it's memory safe and has static
       | typing? What am I missing?
       | 
       | I think any advocate for Haskell has to justify, at minimum, why
       | it should be preferred to all of Rust/Go/Java/Python for a given
       | use case. These all have way better tooling, developer
       | ergonomics, and library support.
       | 
       | (I don't really like Haskell and think it gets a disproportionate
       | amount of buzz here - but I think most Haskell devs would agree
       | with that last sentence. See all the complaints about stack and
       | cabal on reddit, for example.)
        
         | whateveracct wrote:
         | > I think any advocate for Haskell has to justify, at minimum,
         | why it should be preferred to all of Rust/Go/Java/Python for a
         | given use case. These all have way better tooling, developer
         | ergonomics, and library support.
         | 
         | Here's some justification:
         | 
         | - All those languages force me to think imperatively, therefore
         | hamstringing my mind. I don't want to waste time thinking in
         | those languages.
         | 
         | - Haskell has more universal potential. It's obviously a
         | smaller community. BUT I can use Haskell to program FPGAs
         | (clash), embedded systems (Ivory, CoPilot), frontend (ghcjs),
         | write music (tidal, csound-expression, euterpea), shaders &
         | graphics (GPipe, Hylogen), on top of general purpose computing
         | (with a best-in-class FFI to boot.) The nature of the language
         | is such that you can use Haskell for anything and have it still
         | be Haskell - Rust, Go, etc can't get close to that capability.
         | 
         | - None of those languages have tooling at the level of ghci.
         | I've used both Go and Rust extensively and ghci blows their
         | tooling out the water. Cabal is also just excellent nowadays.
         | Haskell also has some of the best testing libraries out there
         | too.
         | 
         | - Haskell has better library support for its community size
         | than those languages. It's substantially easier to find a
         | quality Haskell library on Hackage than a Go one on GitHub.
         | Haskell wins on the quality front, and most gaps imo can be
         | filled easily (API bindings, for instance, are trivial.)
         | 
         | - Developer ergonomics? Haskell's parametric & ad-hoc
         | polymorphism alone combined with its RTS outclass all those
         | languages imo. Go's RTS is worse. All those languages'
         | parametric polymorphism is worse.
         | 
         | ^ all this is true IF you have put in a good amount of time
         | becoming a Haskell pro. For beginners, there are arguments
         | against it. But I'm no beginner so why waste my time using that
         | as my litmus test?
        
         | jmfldn wrote:
         | Agree on tooling and library support. Not sure what developer
         | ergonomics are? Ease of writing code, expressiveness? That's
         | entirely subjective I would say. My subjective take is that,
         | once you know a language like Haskell, it's hyper-productive
         | and simple to express things that would be much harder and
         | error prone in, say, an imperative language. Tradeoff is that
         | it takes a while to get to this point. There is a steep
         | learning curve. It's an amazing tool in the right hands / for
         | the right problems. Tooling etc is such a pain point though.
        
           | spekcular wrote:
           | "Ergonomics" is super vague, so let me give one concrete
           | example. From reddit [0]:
           | 
           | "I'm running Ubuntu so I installed ghc and cabal-install,
           | then installed stack (since people are recommending that) by
           | running their script. Then I found out that haskell-platform
           | is the blessed route (and contains stack) so I uninstalled
           | ghc, cabal, stack and installed that instead. Stack was not
           | installed along with haskell-platform (what? why? ugh...
           | whatever), so I reinstalled it manually.
           | 
           | Great, now I have the tooling all set up! Slightly more
           | irritating than other languages, but it's there.
           | 
           | Now to build my app; I want to give websockets a whirl so I
           | grabbed the server example and stuck it in a newly created
           | stack project (stack new foo worked well) as app/Main.lhs and
           | re-pointed foo.cabal to look at the .lhs extension. Ok, next
           | step is to build it, stack build - it complains that I don't
           | have websockets installed, ok, stack install websockets - it
           | whirrs away for a while downloading stuff and then finishes.
           | That was easy. stack build - same error, still no websockets
           | (???). I take a look through the stack.yml and foo.cabal
           | files and can't find websockets mentioned anywhere (in NodeJS
           | I'd have done npm install --save websockets and it would have
           | both installed the lib local to the project and updated the
           | packages.json file appropriately - same sort of thing with
           | Python via pip + freeze). Presumably I missed the '--save' or
           | equivalent, but I don't see anything like this in the stack
           | install -h docs.
           | 
           | I hop onto irc for help, and am informed that you don't stack
           | install project dependencies; that installs global packages
           | (huh? I thought stack was supposed to help in keeping things
           | local... whatever). Then I find that I have to edit the
           | foo.cabal file manually to add my deps - seriously? Wow.
           | Ok... So I do that (in the wrong place, then eventually in
           | the right place) and finally my stack build works. Awesome!
           | But also grrrr! Why are there two config files talking about
           | libs and how am I supposed to know which one I'm meant to add
           | stuff to?
           | 
           | As an aside there's also the expectation that I should figure
           | out which versions of libs are snapshotted on stackage, but
           | searching on the website funnels me through to hackage (via
           | hoogle) and gives me no indication on the way as to what
           | snapshots they have. I ended up finding the snapshot listings
           | on stackage and using ctrl+f in the browser to figure that
           | out - after checking my stack.yaml to work out what snapshot
           | list I should be looking at. Seriously. These leaps are crazy
           | :)"
           | 
           | I should point out this is from 5 years ago. Probably things
           | are better now. But some things are not, e.g. installing
           | Haskell on Arch Linux [1].
           | 
           | [0] https://www.reddit.com/r/haskell/comments/4sihcv/comment/
           | d5a...
           | 
           | [1] https://dixonary.co.uk/blog/haskell/cabal-2020
        
             | jmfldn wrote:
             | The situation is improving from what I can see but what
             | you're describing is hard to dispute. It's such a shame.
             | 
             | As I say though, I think things are moving in a better
             | direction now (I haven't taken a look at Haskell for a
             | while).
        
             | the_af wrote:
             | > _Great, now I have the tooling all set up! Slightly more
             | irritating than other languages, but it 's there._
             | 
             | Python, which you mentioned in your other comment, is super
             | irritating re: tooling -- yet people seldom find the need
             | to "justify" using it.
             | 
             | Sure, the simplest (and mostly wrong) way of setting Python
             | up is seemingly trivial, just like Haskell's. You'll soon
             | run into all kinds of trouble with pip and dependencies and
             | environments and typechecking and linting and the myriad of
             | confusing and slightly incompatible tools that form
             | Python's wider ecosystem.
        
             | stonemetal12 wrote:
             | It is not unusual to not know what you are doing if you
             | refuse to RTFM. The stack user guide existed 5 years ago,
             | and explains exactly what to do for all the problems your
             | example ran into.
             | 
             | While I get not everyone has the same background, stack
             | works very similarly to how C#, java, rust and just about
             | every other compiled language with its own dependency
             | management system works. His being surprised says more
             | about him that it does stack.
        
           | spekcular wrote:
           | Could you give an example of something that is simple to
           | express in Haskell, but harder and error prone to express in
           | Go/Rust/[other imperative languages]? Honestly curious!
        
             | whateveracct wrote:
             | data Void where         Void :: { absurd :: forall a. a }
             | -> Void
             | 
             | ^ I just defined a type with no inhabitants [1] along with
             | the ability to use a value of it to prove anything. And it
             | leans on the type system features & ergonomics Go & Rust
             | don't even get close to having.
             | 
             | This is a pedantic example in a way, but this type is
             | actually very useful in practice! And defining the type
             | almost reads like English (or at least math English.)
             | 
             | Haskell is just a different world. You program with type
             | variables of different shapes and sizes and relationships
             | like it's nothing and it Just Works. Go's new generics &
             | Rust's are crufty in comparison. Both due to syntax and
             | semantics.
             | 
             | [1] modulo bottom..I know, I know :)
        
             | jmfldn wrote:
             | "Could you give an example of something that is simple to
             | express in Haskell, but harder and error prone to express
             | in Go/Rust/[other imperative languages]? Honestly curious!"
             | 
             | This is hugely subjective but if I'm writing large data
             | transformation pipelines for example, the type system and
             | the compositionsal power of a language like Haskell, or
             | pure FP scala, makes such a task an absolute breeze. It all
             | just slots together like Lego. You have a high degree of
             | confidence that the thing will work, and you can use local
             | reasoning to understand the parts and, by extension the
             | whole program, since the laws of composition and the lazy
             | eval model make this trivial in comparison to imperative
             | code. The way code can compose, the runtime and the
             | resulting local reasoning, can honestly feel like a super
             | power sometimes. Beware of thinking programs written in
             | other languages are simpler to reason about, they might not
             | be. There's more than the "simplicity" of the code to worry
             | about in software.
             | 
             | Is it better than Rust? I can't answer that sort of
             | question, but I can tell you that full-throttled pure FP
             | can be a pretty damn amazing tool when you need it. Rust
             | seems to be a fascinating language for doing, say, systems
             | programming, with some FP-like idioms built in. Amazing!
             | Comparing languages though is tricky, it's always about
             | tradeoffs, context and so on. I don't believe in a
             | hierarchy of languages.
        
             | w4rh4wk5 wrote:
             | I'd say, take a look at error handling. In Haskell you can
             | accomplish a lot by just using `Maybe` and `Either` along
             | with the functions related to them, provided by the
             | standard library. Haskell's pattern matching feature makes
             | it even more straight forward to handle these types.
             | 
             | A lot of this translates to Rust, as Haskell influenced the
             | language design of Rust. In Rust you have
             | `std::option::Option` and `std::result::Result` which
             | relate closely to `Maybe` and `Either`, respectively. Also
             | pattern matching is available in Rust.
             | 
             | When you then look at other (imperative) languages like Go,
             | C, and C++, error handling becomes a bit more cumbersome
             | IMHO. I am not talking about explicit or implicit error
             | handling. It's more about urging the programming to check
             | for and handle errors, and also giving them the necessary
             | tools to do that efficiently.
             | 
             | In Go, you have lots of `if err != nil { return err }`,
             | which is cumbersome to write (luckily we have snippets) and
             | _clutters_ the code. Yes, it is explicit and easy to read,
             | but I don't think error handling should make up 4/5 of the
             | lines of your algorithm.
             | 
             | The same applies to C, more or less, as functions typically
             | tell you about success or failure via their return value.
             | Like `err` in Go.
             | 
             | In C++ we have `std::optional` which is handy, but C++
             | lacks a lot of functional features and convenient syntax to
             | take full advantage of it. No straight forward pattern
             | matching here. There is `std::variant` to create sum types,
             | but I've only seen that in use occasionally. There is also
             | `std::expected` on the horizon, which is similar to
             | `Either` / `std::result::Result`, but adoption will take
             | ages.
             | 
             | C++, being a complicated language, makes it very difficult
             | to just come up with your own wrapper classes that _just
             | work_. See
             | https://github.com/oktal/result/blob/master/result.h for
             | example.
        
             | the_af wrote:
             | Just about anything written in Java requires more
             | boilerplate and rituals than the same function in Haskell.
             | (Or used to, of course: Java has slowly evolved and adopted
             | FP idioms too).
             | 
             | An example: you cannot express in Java "this function does
             | not write to disk", its type system simply doesn't allow
             | it. In order to make sure, you'd have to inspect the code
             | of the function, and the libraries it uses. In Haskell,
             | this is trivial because just by looking at the type of the
             | function you can tell if it's even possible for it to do
             | I/O.
             | 
             | Go requires tons of boilerplate and didn't have generics
             | until recently; there's your answer.
             | 
             | Rust is a bizarre comparison. Haskell predates Rust and
             | Rust takes some (many?) ideas from it or from languages
             | within the same pedigree. Also, I don't know anyone who
             | thinks Rust is "simple", so why ask about this comparison?
             | Write Rust if you want to, no Haskeller is going to
             | complain about your choice.
        
               | spekcular wrote:
               | Rust isn't a bizarre comparison at all. Suppose I have
               | before me some programming task. I can choose Rust,
               | Haskell, or something else. Anyone arguing for Haskell in
               | 2021 (2022?) has to justify why it's a better tool for
               | the job than Rust.
        
               | the_af wrote:
               | Why?
               | 
               | I'm not trying to be dense. Are you saying for every
               | programming language you choose, you make an strict
               | ordering of every existing language and then decide which
               | one you'll pick?
               | 
               | Do you think there is a strict ordering of "is better
               | than" between Haskell and Rust?
        
               | spekcular wrote:
               | I'm saying that programming languages are tools for
               | completing programming tasks. So, yes, when faced with a
               | task I think about which one is best.
               | 
               | Examples:
               | 
               | Need to copy a bunch of files? Use bash.
               | 
               | Need to do a quick Monte Carlo simulation? Probably use
               | Python since it allows me to write it the fastest (based
               | on my familiarity).
               | 
               | Need to write drivers? Use C.
               | 
               | I don't think there is a strict ordering of "is better
               | than" between Haskell and Rust. I think for many purposes
               | they are roughly equivalent, and for some one or the
               | other is more suited to the task.
               | 
               | But, if I can't identify any problem for which Haskell is
               | a better tool than Rust, why would I ever learn Haskell?
        
               | the_af wrote:
               | How can you identify the problem if you first don't learn
               | Haskell?
               | 
               | How would you even decide you want to learn Rust and not
               | Haskell if you didn't know either? Hype? Popularity?
               | Because your coworkers know Rust, or the codebase is in
               | Rust? Those are all good reasons, honestly! So if you
               | were in a Haskell shop, you'd have reason to prefer
               | Haskell over Rust. There's your answer. Either will be
               | better than Python for a medium/large project, but likely
               | worse for a really tiny script or program.
               | 
               | How did you pick Python over Ruby? They are very similar,
               | yet they have many differences. Think about it, and
               | there's another answer for you.
        
               | spekcular wrote:
               | How do I decide? I look at the features and documentation
               | for each language, and try to figure out what problems it
               | is best suited for. I also ask various people I trust
               | (and HN commenters!).
               | 
               | I agree: If the problem is "How do I get paid?" and the
               | best available job requires learning Haskell, then learn
               | Haskell!
               | 
               | But, I think this is kind of an evasive answer. First,
               | not many jobs require Haskell, so if my choice of
               | language is dictated by economic concerns I'm better off
               | with, say, Python or various web dev stacks. Second,
               | because I have in mind a situation in which the
               | implementer has a fixed problem and is trying to figure
               | out which language to use. (A personal project, say.) I'm
               | sorry if this was not clear.
               | 
               | So, I ask again: are there any problems for which Haskell
               | is a better solution than Rust?
               | 
               | edit: Regarding the Ruby question, I think the language
               | has various flaws, but going into detail would take way
               | too time. A shorter answer is: numpy, scipy, pytorch,
               | numba.
        
               | the_af wrote:
               | > _I look at the features and documentation for each
               | language, and try to figure out what problems it is best
               | suited for_
               | 
               | Well, and what have you found so far in relation to Rust
               | and Haskell? It seems to me you know what you have to do.
               | 
               | Let's assume your answer is "I read every introductory
               | page in wiki.haskell.org, read and worked through a
               | couple of tutorials, and I still cannot figure it out".
               | If so, do you think a comment here in HN is going to
               | convince you of picking language X over Y?
               | 
               | > _So, I ask again: are there any problems for which
               | Haskell is a better solution than Rust?_
               | 
               | Realistically, which kind of answer do you expect? A
               | summary of the "Why Haskell" and "Why Rust" pages? I'm
               | sure they exist and you could take a look at them and
               | decide.
        
               | spekcular wrote:
               | > If so, do you think a comment here in HN is going to
               | convince you of picking language X over Y?
               | 
               | Yes. Because I'm a highly fallible person and very open
               | to the idea that a Haskell expert might be able to point
               | out a good use case that I missed.
               | 
               | > Realistically, which kind of answer do you expect? A
               | summary of the "Why Haskell" and "Why Rust" pages? I'm
               | sure they exist and you could take a look at them and
               | decide.
               | 
               | The selling point of Rust is (very, very) roughly "C++
               | without the bad parts, and some more good parts." Given
               | the demonstrated utility of C++ (and demonstrated
               | pitfalls) this is manifestly appealing. Avoiding memory
               | safety related security holes alone is huge.
               | 
               | That's an example of the kind of answer I expect.
        
               | the_af wrote:
               | > _a Haskell expert_
               | 
               | I'm not a Haskell expert, I just dabbled with it and
               | liked it.
               | 
               | > _The selling point of Rust is (very, very) roughly "C++
               | without the bad parts, and some more good parts." Given
               | the demonstrated utility of C++ (and demonstrated
               | pitfalls) this is manifestly appealing. Avoiding memory
               | safety related security holes alone is huge._
               | 
               | The selling point of Haskell is that it's a Functional
               | Programming first language (see: "Why Functional
               | Programming Matters"), has a better statically type
               | system than C/C++/Java which makes whole classes of bugs
               | common in those languages harder to write in Haskell (so
               | if writing correct code is a priority, that's your use
               | case), and memory safety related security holes are
               | harder to write, just like with Rust. Laziness (or non-
               | strictness, whatever) is also a big if controversial
               | selling point (why: read "Why Functional Programming
               | Matters").
               | 
               | If you like slightly less opinionated (or non-strict by
               | default) languages, you could go with OCaml or Standard
               | ML instead.
               | 
               | Why would you prefer Rust? Why don't you ask a Rust
               | advocate?
        
               | spekcular wrote:
               | Rust has better tooling, more direct control in
               | performance-sensitive contexts (no opaque performance
               | traps like, arguably, Haskell), and more
               | community/industry support (meaning more useful and high
               | quality packages). So from the perspective of practically
               | solving problems, it seems better to me. But I could be
               | convinced otherwise by a good argument.
        
               | AnimalMuppet wrote:
               | If you're asking people to learn Haskell in order to find
               | out which kinds of programs it's better on, that's a
               | tough ask in a universe that has dozens of languages that
               | one could learn. Most people aren't going to bite on
               | that. No, tell us what kinds of problems it's good for,
               | and if we care about those kinds of problems, then we'll
               | consider Haskell.
        
               | the_af wrote:
               | > _No, tell us what kinds of problems it 's good for, and
               | if we care about those kinds of problems, then we'll
               | consider Haskell._
               | 
               | Haskell is good for writing general purpose code in the
               | Functional Programming style [1]. It's not the only
               | language that supports this style, but it's one of the
               | most opinionated about keeping to this style that is also
               | general-purpose, pragmatic, and has some industry
               | adoption [2]. You can also see read what wiki.haskell.org
               | has to say [3].
               | 
               | [1] "Why Functional Programming Matters": https://www.cs.
               | kent.ac.uk/people/staff/dat/miranda/whyfp90.p...
               | 
               | [2] Commercial Haskell: https://github.com/commercialhask
               | ell/commercialhaskell#readm...
               | 
               | [3] "Why use Haskell":
               | https://wiki.haskell.org/Introduction#Why_use_Haskell.3F
               | 
               | > _If you 're asking people to learn Haskell in order to
               | find out which kinds of programs it's better on_
               | 
               | I'm not asking people to do anything, but if they do want
               | to understand the tradeoffs of any technology, sometimes
               | the only way is the hard way: learning it. I find all too
               | often what people really want to know is a quick and easy
               | glance at how much language X differs from something they
               | already know (usually C derivatives, or Java, or
               | Javascript, or Python).
        
               | spekcular wrote:
               | Again, I find this answer somewhat evasive. Many
               | languages support functional programming and are used
               | commercially. You still have not told us: What problems
               | is Haskell best for? What is its comparative advantage?
               | 
               | I don't think it's unreasonable to expect a more concrete
               | reply to that quesiton than "First master the language,
               | then figure it out."
        
               | the_af wrote:
               | > _You still have not told us: What problems is Haskell
               | best for?_
               | 
               | Let me be honest here and say I don't find your tone
               | helpful. "You still haven't told us" makes you sound as
               | if you're in a group, critiquing from the tribune. This
               | isn't helpful for honest conversations. There's no "us",
               | there's just _you_ , and _I_ don 't owe you any
               | explanation.
               | 
               | That said, I provided plenty of links in my answer above,
               | which address at least _some_ of your questions. Have you
               | read them? The site https://www.haskell.org has plenty of
               | testimonials that you could also read to figure why some
               | shops and people have chosen Haskell.
               | 
               | Maybe you could send Simon Peyton Jones an email, he's
               | one of the friendliest guys in the software industry. I
               | don't think I've ever read or heard him say anything
               | dismissive about any other person or technology.
        
               | spekcular wrote:
               | I'm sorry, I don't want to be adversarial or dismissive.
               | It's just that I've been asking a very specific and
               | precise question, and you keep replying to the question
               | but do not answer it. This is a little frustrating!
        
               | the_af wrote:
               | But I did answer it, more than once and with links you
               | can read!
               | 
               | What I cannot do: provide you with a single sentence
               | stating why you should use Haskell. I don't think anyone
               | can. For the record, I found your single sentence about
               | Rust totally unconvincing as well; I do find Rust
               | compelling because of tutorials, long articles I read
               | about it, and a workshop I once did with a Rust
               | practitioner. None of this is equivalent to
               | debating/convincing on HN.
               | 
               | (Similarly, I find Go _not compelling_ because I had to
               | use it for my day job and everything about it made me
               | chafe).
               | 
               | So my advice to you: read the links I provided, and keep
               | in mind they are just a starting point. Do a workshop.
               | Work on a midsize problem, maybe also write some Advent
               | of Code Haskell solutions.
               | 
               | Or not. It's ok to just go with your gut feeling and
               | focus on Rust. There's a finite amount of time you have
               | available for exploring technologies. Rust will serve you
               | well.
        
               | spekcular wrote:
               | The question was: For what problem (or problem domain) is
               | Haskell better than Rust? (Back here, for instance:
               | https://news.ycombinator.com/item?id=29595022).
               | 
               | The links you gave provide general information about
               | Haskell, but do not answer that question, from what I can
               | see. I don't want a single sentence reason, just a
               | compelling one.
               | 
               | Again: I'm not doing this to be adversarial. A decent
               | number of people seem to really love Haskell and extol
               | its virtues. So I'm trying to carefully check that I'm
               | not missing something.
        
               | the_af wrote:
               | > _The question was: For what problem (or problem domain)
               | is Haskell better than Rust?_
               | 
               | Haskell is a general purpose language, so it's good for
               | any domain well served by a general purpose language. The
               | rest is the list of benefits of statically typed, lazy
               | first, pure functional programming languages.
               | 
               | "Haskell or Rust?" is not a question that can be
               | meaningfully and objectively answered in a comment on HN.
        
               | w4rh4wk5 wrote:
               | From my experience it is a pretty tough question to
               | answer. You can point people to various 'smaller' aspects
               | (like I did above regarding error handling) and try to
               | explain why Haskell's approach is 'better' compared to
               | other languages. But doing that for a complete, real-
               | world problem is a lot more difficult.
               | 
               | I've learned Haskell and used it for a relatively long
               | time until I finally understood what is so nice about it.
               | Again, very hard to explain, and a lot of that comes just
               | from the combination of simple, functional language
               | features. Like: how currying works together with function
               | composition; how sum-types and product-types make it easy
               | to model your domain / problem and using pattern matching
               | to write code that is easy to understand and does the
               | right thing; how a powerful type-system can be leveraged
               | to rule certain bugs out almost completely, right from
               | the design phase. Leveraging monads by using Haskell's
               | special `do` syntax.
               | 
               | I only really understood this after having done
               | imperative style programming, then having done functional
               | style programming, and then trying to apply the
               | functional style in an imperative environment and seeing
               | why it does not work there (typically because of some
               | missing language feature).
               | 
               | Edit: Just wanted to point out, I am not a fan of Haskell
               | as a whole, since there are a lot of drawbacks in my
               | opinion. There are valuable things to learn from the
               | language, but I do think Rust is superior.
        
               | [deleted]
        
               | AnimalMuppet wrote:
               | No, he kind of did answer it. "General purpose code". He
               | didn't say "it's for web programming" or "it's for hard
               | real time" or "it's for numeric analysis". I mean, you
               | can probably write web programs in Haskell, but if that's
               | what you're trying to do, you might reach for something
               | else. Same for numerical analysis. For hard real time you
               | would almost certainly reach for something else. But if
               | your program doesn't fit in a "use something specialized"
               | category, and you want to write in a functional style,
               | then consider Haskell. That seems to me to be a perfectly
               | reasonable answer.
               | 
               | And the rest of the answer is, essentially, "beyond that,
               | if you want to see, you're going to have to learn it". I
               | also don't find that unreasonable - there's only so much
               | you can explain to someone who doesn't know the language.
               | And that's not just Haskell, that's _any_ language. I
               | kind of have an idea of what Rust is about, but if I want
               | to really understand it, I 'm going to have to learn it.
               | Same with Haskell, or Lisp, or pretty much anything.
               | 
               | So I found the_af's answer to be quite helpful. And I'm
               | the guy who asked the question, so...
        
               | youerbt wrote:
               | > Anyone arguing for Haskell in 2021 (2022?) has to
               | justify why it's a better tool for the job than Rust.
               | 
               | You ask for a lot of reasons considering the amount you
               | dare to provide. No, nobody has to do that, it doesn't
               | make any sense. Let Rust people comment under articles
               | about Haskell why Rust is the better choice.
        
         | nicoburns wrote:
         | > Is this argument here just that it's memory safe and has
         | static typing? What am I missing?
         | 
         | I think the argument is that it provides _stronger_ static
         | typing than any of those languages, with only Rust being close
         | out of the other languages that you list. This allows you to
         | encode business logic (incl. security logic) invariants into
         | the type system and catch a lot _more_ errors /bugs at compile
         | time.
         | 
         | The step up from Java to Rust/Haskell in terms of static typing
         | capabilities is at least as big as the step up from python to
         | Java.
        
           | spekcular wrote:
           | Sure. So I would like to know: What is a use case where
           | strong static typing is a major advantage, and where Haskell
           | is clearly better than Rust from a language design/feature
           | perspective?
           | 
           | edit: Another question. Is there a language that has stronger
           | static typing than Rust without the weird performance
           | pitfalls and subpar tooling that Haskell has? I can imagine a
           | project for which such features would be useful, but getting
           | over those two issues is difficult.
        
             | the_af wrote:
             | > _What is a use case where strong static typing is a major
             | advantage_
             | 
             | Writing correct code with fewer bugs.
             | 
             | Catching bugs earlier.
             | 
             | Not having to write unit tests for things the compiler can
             | figure out for you, leaving you free to write the actual
             | meaningful tests.
             | 
             | Making code self-documenting with types, leading to less
             | puzzlement.
             | 
             | ... just to name a few.
        
               | simiones wrote:
               | While there may be some correlation between _some_ static
               | typing and less bugs, there _definitely_ isn 't a linear
               | relationship: stronger type system => fewer bugs.
               | 
               | In particular, strong types past some point start
               | exploding code complexity for any kind of polymorphic
               | code. My favorite example is adding strong typing to
               | linear algebra operations, via units of measure for each
               | element of a matrix. Try to find a library that can
               | multiply matrices where each element can be a different
               | physical quantity (of course, validating first that the
               | two matrices can actually be multiplied) - say,
               | multiplying (1m 2s-1) * (2s-1 1m) = 2m/s + 2m/s = 4m/s;
               | but not allowing (1m 2s-1) * (2m 1s-1), since it would be
               | 2m2 + 2s-2.
               | 
               | Even if you can find such a library, it will be
               | significantly more complex than an equivalent linear
               | algebra library that is less strongly typed (one that
               | only handles matrices of numbers, without units of
               | measure).
        
               | the_af wrote:
               | I didn't claim there is a linear relationship. It's
               | enough for me that there is a relationship. The OP asked
               | "what's the use case" and I gave him several that ring
               | true to me.
               | 
               | Whenever I write Python , I wish I was writing Haskell.
               | No need to ask about artificial examples of linear
               | algebra; just my boring day to day code in Python would
               | benefit from having Haskell's type system. And yes, I do
               | know about static typing for Python -- I find it's
               | _worse_ , tooling and effectiveness wise, than an actual
               | static type system.
        
               | simiones wrote:
               | Well, GP was asking about Haskell vs Rust, not Python;
               | and the discussion before was about Haskell vs Java as
               | well.
               | 
               | And the example I gave is not entirely artificial - units
               | of measure are often measured as an advantage of strong
               | type systems, something that could potentially avoid the
               | Ariadne disaster, and I find this common example
               | unconvincing.
        
               | the_af wrote:
               | The GP also mentioned Python in another comment, and
               | specifically asked "what about strong type systems",
               | which makes the comparison to Python relevant.
               | 
               | > _something that could potentially avoid the Ariadne
               | disaster_
               | 
               | Haskell or any language with modern static typing would
               | definitely have helped. You wouldn't be mixing unit types
               | and confusing them like it happened (if I remember
               | correctly) with the Ariadne. Would it have been enough? I
               | don't know! But it would have helped! Any measure of
               | static and dynamic analysis would have helped for mission
               | critical software, and it's evident the Ariadne had some
               | serious deficits in this regard.
        
             | [deleted]
        
         | stank345 wrote:
         | I'm not a seasoned Haskell dev by any means, having only played
         | around with it for parsing and then more recently for Advent of
         | Code, but tooling has come a _long_ way in the past 6 months. I
         | was able to use ghcup to very easily install and manage
         | versions of GHC, cabal, and HLS (Haskell Language Server), the
         | LSP server that the community has thrown all of its energy
         | into. All I had to do then was configure the LSP client for my
         | editor and _everything just worked_. I had function signatures
         | /docs on hover, go to definition, and symbol renaming working
         | in about a half hour.
        
         | the_af wrote:
         | > _I think any advocate for Haskell has to justify, at minimum,
         | why it should be preferred to all of Rust /Go/Java/Python for a
         | given use case_
         | 
         | At least the preference of Haskell vs Python is easy to
         | justify: Haskell has a top-of-class static typing system and
         | Python doesn't, which if you believe static types lead to
         | better code (which I do), makes it clear why you'd prefer
         | former. Whole classes of mistakes which are easy to create
         | inadvertently using Python simply go away (or are very
         | difficult to commit) using Haskell. If you care about code that
         | is correct and with fewer bugs (on a continuum, of course) then
         | that's your justification.
        
           | AnimalMuppet wrote:
           | You might - _might_ - be able to create those same bugs in
           | Haskell. But you 'd probably have to deliberately try. (They
           | might be impossible even if you deliberately try to create
           | them.)
        
             | the_af wrote:
             | You might indeed, but you'd have to go out of your way.
             | Whereas with Python I write those bugs as easily as I
             | breathe. Maybe I'm just a bad programmer; static types are
             | definitely good for those like me. If that's not a
             | practical, non-ivory tower reason to prefer Haskell, I
             | don't know what is!
        
               | AnimalMuppet wrote:
               | Yeah. My memory's not good enough to not use static
               | types.
        
       | heresie-dabord wrote:
       | Security matters. Any discussion about security is good, even if
       | in the worst case the speaker is a $myLanguage bigot. Because we
       | have learned once again with log4shell that... security matters.
       | 
       | The OP writes,
       | 
       | "Software Security has no universal theory on which to rely.
       | Security is most often taught by enumerating different security
       | issues, mitigations and security models and hoping that students
       | can build from them to gain general understanding. Even of those
       | theoretical works that exist, relatively few of try to build a
       | link between programming language and security aspects."
       | 
       | Compilers and IDEs can improve. Where all the security effort
       | clearly wanes is at the right of the OP's "technical --> tooling
       | --> thinking" spectrum.
       | 
       | A modern language should be memory safe... But general language
       | safety must extend to dependency management and package
       | repositories. Without competent dependency management and fully-
       | secured repositories of vetted code, we still have a professional
       | community of very proud dumpster fires.
        
       | tptacek wrote:
       | Nobody really knows; it's not in widespread enough use to have
       | been seriously researched.
        
         | stunt wrote:
         | Sadly true. As amazing as Haskell way of thinking is, most of
         | the time (if not always), is a bad choice for building anything
         | because you can't find developers to work on it.
        
       ___________________________________________________________________
       (page generated 2021-12-17 23:02 UTC)