[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)