Lets talk about Haskell

I'll say this upfront, I fucking love the language but hate the tooling. I've completed a few projects in Haskell, nothing big, but usable software and here are some of my thoughts.

>cabal is the worst packaging system ever imagined
>stack uses cabal
>a simple stack project uses gigabytes of disk space for a small project
>build times are really really bad
>bindings to gui libraries are generally shit
>haskell qt bindings are especially shit, try getting them to work on something other than linux and you'll know what I'm talking about
>there are no ghc builds that are compatible with the official qt builds, so you have to build both qt and ghc yourself on windows and make that work with stack. have fun.
>ghc's build system is atrocious, especially so on windows (this is also acknowledged by the development team, but they don't have anyone that actually wants to revamp it)
>hackage sucks. there is no way to know what library to use or which one is good and before you know it, you're using a library that isn't a good fit for your project and you waste time. the rating system is also useless.

My biggest gripe with Haskell however, is that you don't actually learn the language, you learn the library that you are using.

Every library does everything differently. There are thousands of different concepts which are used by libraries and you'll have to learn every single concept because there is no standard or generalized way to use the libraries. Some libraries use lenses, some use StateT, some use EitherT, some use ReaderT, some use WriterT, some use ExceptT, etc. etc. etc. the possibilities are endless.

Now, when you have learned the concepts and how to use a library, you have to learn to make them work nicely with each other.
The most fun part about that? Some concepts are mathematically incompatible with each other and can not be combined.

What are your thoughts on Haskell? Have you written a program with it?

Attached: serveimage.png (1200x847, 15K)

Other urls found in this thread:

dev.stephendiehl.com/hask/#eightfold-path-to-monad-satori
twitter.com/AnonBabble

>you don't actually learn the language, you learn the library that you are using.
Isn't that the case for all languages?

I didn't learn it, but I don't like purism. Some algorithms are just so simple to be implemented procedurally (iterative loops), why would you force a recursive solution?

Not really. The libraries for imperative languages generally have a very simple way to use and combine them. Look at any C libary and the pattern is usually the same: create resource, call function and pass resource and a few variables as arguments, destroy resource. Even in more complicated cases it doesn't take very long to figure out how to use a library, because the concepts are all very similar.

You can program imperatively in Haskell if you really wanted to. It even has libaries fot loops.

Been using it for work and it's been pissing me off. As soon as you touch any moderately powerful language extensions, or even use libraries that use extensions (even basic shit like ST or StateT), the type inference stops "just werking". But the whole language is designed around the assumption that type inference always works, so when it breaks, getting the right type signatures down is a pain in the ass (and sometimes literally impossible, unless you turn on even more shitty language extensions).

At least with Coq, they know their type inference is shit, and they make it easy to provide partial annotations for the inference to fill in later. Plus, Coq is actually designed for doing complicated things with type variables, so you don't need a god damn language extension just to refer back to a type variable bound in an outer scope.

Also, kind of this: . Any nontrivial imperative code with monads is awkward as fuck, and yet monadic Haskell has basically no real benefits (safety or otherwise) over imperative Rust, unless you start getting into the real wacky monads like Cont or reverse state.

BTW, pro tip for you OP: install nix, delete cabal. If you use nix to set up all your build environments, you can literally build your project with ghc --make, and never need to touch cabal.

There was some partial type annotations extension for GHC.

I refuse to give Haskell a try until I can hear 1 fucking half-competent explanation of what the FUCK monads are.

Because recursion is kinda like induction and you can reason inductively on your function. Proving that it does what you think it does is much easier with recursion that with loops. Actually if you wanted to prove that a loop does what you think it does you'd fall back to induction and end up with a proof similar to recursive program. Recursion leaves less space for guesswork. Note that purely iterative loops are trivial in Haskell:
iterate :: (a -> a) -> a -> [a]
-- e. g.: iterate (+1) 1 = [1, 2, 3, ...]

It's when there are complex effects that Haskell gets complicated because you need to very precisely describe them.

>Any nontrivial imperative code with monads is awkward as fuck
True, there's no denying that it's awkward at best.
>Haskell has basically no real benefits (safety or otherwise) over imperative Rust
I was thinking about giving Rust a shot, do you have any experience with it and would you recommend it over Haskell?
What really blew my mind the first time I used Haskell was that after writing my program and it successfully compiled, it "just werked" and even to this day it doesn't have a single bug (that I found) and I've been using my own program more than half a year by now.
Is Rust similar in that regard?

>BTW, pro tip for you OP: install nix, delete cabal. If you use nix to set up all your build environments, you can literally build your project with ghc --make, and never need to touch cabal.
I've heard good things about nix for Haskell so I'll give it a shot. It doesn't work natively on Windows though, does it? I need my programs to work on Windows as well, as I mainly create cross platform software. I'd probably still consider it for development only, even if it doesn't work on Windows.

All told, a monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor.

i'll write it in terms of C++ types:
okay so you have some kind of container type foo and you have a function that accepts an unrapped variable and returns a new one inside that container (the signature will be foo fun(T))

in the simplest terms, fun is a monad if you can define some kind of apply operator that accepts an argument of type foo, unwraps it, and passes it through fun to get another foo out the end (instead of e.g. foo)

there are some other mathematical laws it has to follow as well but that's the basic idea to wrap your head around

>I refuse to give programming a try until I can hear 1 fucking half-competent explanation of what the FUCK void (*)(void*) is
That's how you sound. Try explaining it to somebody who has never programmed. But I'll try to dumb it down for you anyway: monads are algebraic structures (replace these two words with "things" if it irks you) that can be used to represent sequences of things. Like sequences of input/output actions. That's it. You get (for a given monad m:
bind :: m a -> (a -> m b) -> m b

to sequence an action m a (action with result value a)with a following action a -> m b (action that takes a as input and outputs b. The result of the whole sequence is obviously an action that returns b.
You also get return :: a -> m a which is an action that simply returns its input.

>My biggest gripe with Haskell however, is that you don't actually learn the language, you learn the library that you are using.
Good point, OP. DSLs suck.

I almost understand this except I don't

I also love Haskell, I'm currently at that point when you can already write Haskell, you have done all the toy programs in the book, but I just can't with most libraries external libraries yet, everything feels like a rabbit hole.

Like you mentioned, there seems to be a big problem of standardization in haskell, everything feels too opinionated. There is no "Haskell way" to do things, which is both blessing and a curse.

>cabal is the worst packaging system ever imagined
Yes, that is why you should only use it as a building tool. Use nix as a package manager. This meme "every fucking language NEEDs (because muh ecosystem) it's own fucking package manager incompatble with other languages" needs to die.

>relying on the garbage that your bistro ships for development
no

>lenses, some use StateT, some use EitherT, some use ReaderT, some use WriterT, some use ExceptT
These are all different concepts for different things. You can't use EitherT in a place for ReaderT. OP is just retarded and doesn't know what he is talking about.

Here you go senpai:

dev.stephendiehl.com/hask/#eightfold-path-to-monad-satori

>>relying on the garbage that your bistro ships for development
excuse me, what? can someone translate that

The translation: Fucking plebians.

the virgin haskell vs the chad lisp

This. Also people give Java, C#, etc. a pass for much worse shit.

>everything feels like a rabbit hole.
Pretty much.
Oh, I'm retarded because I didn't add Maybe as another example. Go fuck yourself you autist.
You also didn't read my post properly:
>different concepts
That does not imply different concepts for similar things. Opinion discarded.
You can't compare the Java or C# library ecosystem to the Haskell one. Two of those have large standard libraries with which you can write most programs.
Haskell would need some kind of standard way to write libraries, so that you don't have to learn every single library out there, just to know how to call the function you need to use.

All the T's (ReaderT, WriterT, etc) follow the same convention, so I wouldn't say it's that horrible. I would focus less on finding "The Best Way" and more on getting shit done. When all is said and done, it's the only thing that matters. Plus you have referential transparency, so refactoring isn't such a pain in the ass.

>I was thinking about giving Rust a shot, do you have any experience with it and would you recommend it over Haskell?
Use the right tool for the job, of course, but Rust is definitely worth checking out. It's got a strong type system, pattern matching + ADTs, and "traits" which are basically typeclasses + type families but cleaned up and simplified a bit. It takes a while to fully understand the rules around references, but once you do, it gives you some of the clarity about possible side effects that Haskell provides through monads.

>after writing my program and it successfully compiled, it "just werked"
>Is Rust similar in that regard?
Yeah. I mean, that's pretty much what happens when you have memory safety and a real type system. Rust has no null pointers, for example - instead, you use something like Option (similar to Haskell's Maybe) which requires pattern matching to use the inner value (or do something else if it's not there). There's still .unwrap(), which is the fromJust equivalent, but of course it's considered bad style to use it.

>It doesn't work natively on Windows though, does it?
Ah, nope, you'd need a VM or maybe mess with WSL. And if you need Windows binaries out at the end, I guess you'd need a cabal setup anyway for the final build.

Nix makes it pretty easy to override parts of packages. You can say things like: "give me a shell with packages X, Y, and Z installed, but with version 1.2.3 of Z instead of what's currently in the repo, and also bump X's dependency Q to version 4.5.6". And you can pin it all to a specific snapshot (literally a git revision) of the nixpkgs repo, so no worries about the distro switching versions in a way that breaks your shit. If you need something that's not in the repos yet, for most languages there are scripts like "cabal2nix" that will generate a nix package from a .cabal file.

>>some use StateT, some use EitherT, some use ReaderT, some use WriterT, some use ExceptT
>some libraries have internal state, some have functions that can fail, some read stuff, some write stuff, some have functions that can fail (this one is actually repeated because EitherT is depracated iirc)
>this is somehow strange
>>hackage sucks. there is no way to know what library to use or which one is good and before you know it, you're using a library that isn't a good fit for your project and you waste time. the rating system is also useless.
I thought hackage was just a repository/database. I don't see why it should do anything more, just like apt shouldn't tell me which pdf reader I should install.

Can you make all that Haskell nix stuff work with GuixSD? I know (/have heard) GuixSD has the same tooling underneath but I don't know how far the similarities reach.

What Haskell nix stuff?
I'm not that user, but I use GuixSD and I frequently create my own packages (derivations) for it for software that isn't in their repos yet, and I often do it by first looking at the Nix package. A lot of it is almost a 1:1 translation. So it's pretty easy to make anything that works on nix also work on guix.

GuixSD is a distro, we are talking about package managers here. You can use nix on whatever linux distro (and on macos) you want.

That being said, you probably can use guix (the manager) in the same way, but I have never looked into it. There is a ton of literature on how to use nix with haskell, and none for guix, so if you intend to make it work you will have to figure it out by yourself.

Monads are programmable semicolons.

Cześć Michał

This is probably the worst description possible.

Moreover, the IO monad is by far the dullest monad of all.

Lousy definition indeed

>Moreover, the IO monad is by far the dullest monad of all.
I think of the Maybe monad when I imagine programmable semicolons. What if you could code C# with every ; meaning "if (lastresult == null) { return null; }"

I agree mostly.
In the past I used it often.
It's a good language in concept, but not good for writing projects in because they managed to fuck pretty much everything up.
If I want to get something done I now use go or c.
Those two are pretty much 100% of what I need to actually do stuff.
Even c would probably be enough, but sometimes you just want things to get done more quickly and not worry, which is where go is better.

monads are containers that a apply to all function, a create container of 1 function, and a combine container of containers function.