
A Taste of Haskell - def-
https://hookrace.net/blog/a-taste-of-haskell/
======
agentgt
As for the Java bashing in the beginning I'm not saying Java is anywhere near
the expressive power of Haskell but many people think different things based
on Java because of features they either don't know about, outdated libraries
used, or experiences with older versions and codebases.

For example most don't know that Java actually does have macro like
capabilities through APT (annotation processor that will work automagically I
might add). Some might say ewww its not macros but then again annotation
processing might just be 80/20 good enough (aka what OCaml learned with ppx vs
camlp) and that Java now sort of has traits and that its code swapping is
actually fairly good (jrebel). There are even sadly people that don't know
Java has lambdas, and even some (usually C++ dudes) that don't know it has
generics. Most don't even know that you can combine interfaces with generic
types as in: `<T extends Comparable & Serializable> void someFunc(T t)`.

Yes Java is not Rust, Haskell or even OCaml in expressiveness but it certainly
is more powerful than Golang and definitely compiles fast (albeit starts up
slow).

That being said OCaml is still my favorite. Compiles fast and easier for me to
understand. Super mature and lots of companies use it.

~~~
iLemming
It's not Java what makes Java platform one of the most popular but rather JVM.
That's why Clojure grows in popularity. Because it brings the expressiveness.

~~~
oweiler
Please show me how Clojure is growing in popularity. Clojure has never been
more than a niche language.

~~~
ardacinar
A language can grow in popularity while still remaining a niche language.
Haskell is a very good example of that, but I really can't say the same thing
about Clojure.

~~~
adrianN
[https://xkcd.com/1102/](https://xkcd.com/1102/)

------
sa1
That's not really the Sieve of Eratosthenes. The list data structure is not
well suited for the algorithm. See [1] for a proper discussion. As someone who
wants to write Haskell(and loves it) for code with mathematically well defined
guarantees, the propagation of such examples, where the guarantees or behavior
is not clear to the author, is not helpful.

[1]: [https://www.cs.hmc.edu/~oneill/papers/Sieve-
JFP.pdf](https://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf)

~~~
pera
It's the same example displayed in haskell.org though.

~~~
seagreen
Totally fair point. haskell.org has a very . . . casual approach to presenting
the language. It's been such an issue some people made an alternate homepage
at haskell-lang.org.

------
TheAceOfHearts
I got started with Haskell recently, and I'm really regretting not having
picked it up earlier. Most of what I knew about types came from C, C++, or
Java; so it's a big leap.

I've been using Haskell for Mac IDE [0] while experimenting, and it's been
great fun.

The thing that prompted me to give Haskell a a try was this video [1] of a guy
using Haskell to generate Elm types, in order to maintain consistent types
across the stack. This idea captivated my interests. I'm confident that
GraphQL and Relay, or something along those lines, is gonna be the future.

My experience so far has been that Elixir feels more welcoming and beginner
friendly. There's nothing wrong with the Haskell community (or my limited
interactions with it so far), but so far it's just felt a bit drier.

[0] [http://haskellformac.com/](http://haskellformac.com/)

[1]
[https://www.youtube.com/watch?v=sh4H8yzXnvw](https://www.youtube.com/watch?v=sh4H8yzXnvw)

~~~
acchow
If you delve deep enough into C++ TMP, it's just as expressive (more
expressive in some ways) as Haskell. You can actually do dependent types in
C++.

~~~
deckiedan
From what I understand, C++ can do _anything_! But sadly, it lets you do
anything.

Haskell restricts what you can do hugely. But also lets you accomplish a whole
lot within what it thinks of as safety.

I like Haskell - but think it's really just a playground for trying how far
functional purity can be pushed, rather than being the actual best version of
that paradigm.

Probably in 10-20 years time there will be a language around which takes all
those concepts and comes together as a really pleasant unsurprising friendly
developer experience. Maybe it'll come from slow evolution of Haskell... stack
helps a lot, and a whole bunch of GHC extensions... but it's still got a lot
of very impractical elements and hangovers from the past that really need to
go.

~~~
silluk
It's a far cry from Haskell but I've found Rust's type system to be a breath
of fresh air coming from C++. Stuff like destructuring assignment and matching
on enums (or anything really) while not as powerful as their equivalents in
Haskell, are still much nicer than what you can do in C++.

------
Dzugaru
Don't know about Haskell, but what really got me (a long time CSharp
programmer) into functional programming was this awesome site [1] (and a man
behind it with his awesome talks) - which is focused on core aspects of FP
(applicable in most languages nowadays) in real-world applications.

[1] [https://fsharpforfunandprofit.com/](https://fsharpforfunandprofit.com/)

~~~
shados
I love that site. The best part about it is that it gives you all of the
common names for stuff like category theory concepts. Eg: the various ways
map, flatMap, bind, etc are called across languages.

Because its a pain in the ass to learn those concepts from scratch when you're
looking at code in one language but reading a tutorial in another...the
concepts are language agnostic, the naming conventions however are not.

------
androidfox
Nice link. One related question : where have you used Haskell in real life. Do
some top companies use Haskell to solve problems

~~~
wuschel
I second this question and would like to add another one:

Where is it that Haskell shines?

~~~
jfoutz
There are a bunch of fussy little problems that Haskell solves nicely. One
example is looking up a value in a map

    
    
        map.get("foo") // returns null
    

is the value of the key null, or was there no key? Different languages have
different approaches. Haskell let's you build up deep structures, a list of
maps of list of maps ... and you'll have an indication of what path you took
down the data structure to get a result. You _can_ do this in any language,
but it relies on programmer discipline, and everybody doing it the same way
every time. In Haskell, it's the easy thing to do, and often the only way to
do it. You'll wind up with something like

[Just ["foo"], Just ["bar"], Nothing]

The first two maps had once answer each, the final map had nothing.

Laziness means you have control of the order of evaluation. in practice you
can make your own control structures without macros. bracket is a good
example,

    
    
        bracket open_socket do_stuff close_socket
    

the socket always gets cleaned up, with an ordinary function. No try/catch.

One of the biggest hassles in programing is leaky abstractions. The type
system means you can steal abstractions from mathematicians that just don't
leak. There's some good stuff here [1] about the kinds of things you can say.

Purity means values can't change behind your back. there's no function to call
that'll change the state of some object you're working with.

All together, it's nice for languages. You can build up parse trees any way
you wish, and traverse those trees to execute the semantics. So if you can
think of a dsl for your problem, you can whip up an interpreter pretty quick.
If you change your mind, and want to turn it into a compiler, it's relatively
painless.

It's a fun language.

[1]
[https://wiki.haskell.org/Typeclassopedia](https://wiki.haskell.org/Typeclassopedia)

~~~
z1mm32m4n
I'm writing a compiler in Haskell for a university class this semester. I
don't think "painless" is the word I would use to describe it. Would you care
to elaborate on your thoughts here?

~~~
jfoutz
Sure :) First, i have to say i feel your pain. Writing a compiler is hard. If
there's anything left you don't understand, this project will be punishing.
Just know that at the end of the semester, there is absolutely no magic left.
Your mental model of computation will be spectacular. Hang in there.

There are a couple of things. First, haskell lets you build up the language
incrementally. So if your parse tree is like

    
    
        data AST = Prim Op |
                   Immediate Int 
    

you can just throw in

    
    
                   Variable String
    

And the compiler will tell you all the functions with non-exhaustive matches.
It's tough to do this in C because you have to remember all of your
switch/case statements. Also, in C those switches are going to be based on a
tag in a data structure rather than a direct type. The compiler won't really
help very much.

Second, the thing that implements the semantics for the parse tree can be a
typeclass.

    
    
        class Semantics where
            eval (Prim op) :: Prim -> a
            eval (Immediate i) :: Immediate -> a
            eval (Var name) :: Variable -> a
            
    

In haskell, you are free to implement an interpreter which is way way easier
than a full compiler. It's nice to have an interpreter for your language,
because you can run the same program both ways, interpreted and compiled.

so...

    
    
        instance Semantics Interpreter where
            eval (Prim op) = case op of
                Plus l r = eval l + eval r
                Minus l r = eval l - eval r
                ...
            eval (Immediate n) = n
                ...
            -- variables need an environment, but i think you get the idea, just look up the string in the env.
    

Then, you can write a compiler.

    
    
        instance Semantics Compiler where
            eval (Prim op) = case op of
                (Plus l r) = eval l ++ "MOV r1 r2 \n" 
                          ++ eval r "ADD r1 r2 -> r1\n"
                ...
            eval (Immediate a) = "STORE " ++ a ++ " r1\n"
                ...
            -- again, variables require an env to be passed around, it's just another arg to eval
            -- this time around though, instead of a simple lookup
            -- you need the memory address to load into r1
            -- you have to encode what lookup would do. 
            -- [2] talks about this a bit.
    

This is a pretty crappy evaluation strategy, just sticking the last result in
r1, but i'll work. You can do much much fancier things.

Another super cute trick with haskell, you can use LLVM to generate your
machine code at haskell run time, and then dynamically link it [1]. This lets
you mix and match evaluation, interpret parts, compile parts, and use them
interchangeably. Much much easier debugging. That link should get you
generating machine code for a toy language in a day. Basically, instead of
loading up the dynamic library, you just make an executable instead.

Anyway, there's lots of good stuff out there. I'd suggest out 3imp [2]
(warning postscript file) That's Kent Dybvig's dissertation on writing scheme
compilers. The second implementation is unbelievably elegant. full support for
call with continuation, so much cool stuff. It compiles to a VM rather than
assembly, but that makes a lot of complex things clear.

An obvious typeclass is a pretty printer for your parse tree, so you can make
sense of what a program is supposed to be doing and you don't have to swear
quite as much when your resulting assembly doesn't work.

A less obvious typeclass pass is a typechecker, if someone is adding a string
to an integer, you can return a new AST that injects the Int -> String
conversion. Constant folding is a good one to do as well.

An even less obvious typeclass will ensure that every malloc has a free. I
don't think it's possible for any C program, but you can get a lot of it, and
spit out a warning when your algorithm isn't sure.

If you can handle academic papers, Oleg's finally tagless is the coolest way
to swap out interpreters, compilers, and partial compilation [3] (pdf)

C won't help you with that, like at all. you can play a game with a table of
function pointers, that you swap out for the various eval cases. Debugging
that, imho, is hard. With haskell the compiler just tells you you're being
dumb.

I guess the main thing is, a compiler has a ton of special cases. Half the
battle is just mananging those special cases. Haskell eases a lot of those
burdens. The other half of the battle is coming up with good algorithms for
getting stuff done (like register selection above!). Haskell lets you slice
things up, so you can give your algorithm everything it needs to do its job
efficiently. It's not that you can't do that in other languages (clearly,
there are a ton of compilers in a ton of languages) it's more that it really
encourages and supports the kinds of things you need to do when writing a
compiler.

Again, writing compilers is hard. you will feel stupid. You are not stupid,
you're doing something very few of the 7 billion people on the planet have
even attempted. It takes years of practice to get good enough to even try.
You're a badass. You'll solve it.

[1] [http://augustss.blogspot.com/2009/01/llvm-llvm-low-level-
vir...](http://augustss.blogspot.com/2009/01/llvm-llvm-low-level-virtual-
machine-is.html)

[2] ftp://www.cs.indiana.edu/pub/scheme-repository/doc/pubs/3imp.ps.gz

[3] [http://okmij.org/ftp/tagless-final/JFP.pdf](http://okmij.org/ftp/tagless-
final/JFP.pdf)

 _edit_

In retrospect that register allocator blows. any right associative operations
will get stomped on. It's what i get for slapping something together at 1 am.
let's just pretend this is for fourth, and you always work on the top of the
stack.

------
mahyarm
I really want to warn people from using long-to-compile languages in big
projects. And by long, I mean longer than C++. From what I heard Haskell has
compile time issues.

You will regret it once your in that position and it is hard to get out of
once your there.

~~~
dkubb
It's a common misconception that Haskell is slow to compile but not really
true, see for example: [http://www.shimweasel.com/2016/10/24/fast-tests-and-
static-l...](http://www.shimweasel.com/2016/10/24/fast-tests-and-static-
languages)

~~~
Athas
I guess it depends on your expectations. I'm working on a ~38000 SLOC Haskell
program (an optimising compiler: [http://futhark-lang.org](http://futhark-
lang.org)), and with GHC 8.0.1, a full build takes about 7 minutes. I can cut
off a minute or two by passing `--fast` to Stack. However, even small
incremental builds take a significant amount of time due to linking, which is
what annoys me the most. It's still far from making me disavow Haskell, but
it's definitely not among the fastest-compilable languages.

This program is also too big to load in GHCi, at least on my laptop with 8GiB
of memory.

~~~
mahyarm
That's pretty uncanny, swift has a fairly sloc to time ratio too. The memory
usage although is significantly less.

------
joobus
I've spent quite a bit of time with Haskell, and all the beginner text like
this link are easy to grok, but where I've constantly come up short is trying
to write an app with, for example, a configuration and a database connection.
Having multiple levels of Monad transformers just confuses me and I never get
anywhere useful. Something like:

App MaybeT IO (StateT IO (EitherT IO Text SomeRecord))

Or something. I haven't figured this out.

~~~
spion
Use IO for everything at the beginning. Use wai/warp to run an app directly
and setup handlers. Use postgresql-simple to send queries. Read the settings
object once, then pass it everywhere.

You can slowly start writing generic types for your pure code after a while.
For example, replace types such as `[t]` with `Functor f => f t` if the only
list-related operation done in that function is `map` (fmap). Try to take
advantage of the stuff here:
[https://wiki.haskell.org/Typeclassopedia](https://wiki.haskell.org/Typeclassopedia)

After a while of doing this, you can start looking into how you can write your
code in a way to have more generic types, then specialise it for the concrete
problems you're solving

Finally at this point transformers should become easier and more obvious.
Perhaps the first one would be to replace passing the config everywhere with
ReaderT. Implementing a few transformers by yourself should help. Start with
MaybeT and continue with ReaderT. Tip: `liftIO` magically works but you don't
have to always understand how. Maybe also try free monads if transformers seem
too annoying!

~~~
spion
I almost forgot; use MVar [1] to keep mutable state around. Its seriously
helpful.

[https://hackage.haskell.org/package/base-4.9.0.0/docs/Contro...](https://hackage.haskell.org/package/base-4.9.0.0/docs/Control-
Concurrent-MVar.html)

------
cies
There are some book recommendations at the bottom of the article, which are
missing the (IMHO) latest-and-greatest introductory resource to Haskell: the
book Haskell from First Principles.

[http://haskellbook.com](http://haskellbook.com)

------
KennyCason
I love Haskell, but if you hate Java, but still want to leverage the nice Java
ecosystem, (libs, IntelliJ, JVM, tooling, etc) try Kotlin! :)
[https://kotlinlang.org/](https://kotlinlang.org/)

~~~
whateveracct
If you love Haskell I guarantee you will not love Kotlin in the same way. Your
best overall bet for Haskell-like FP on the JVM is Scala+cats/scalaz and other
Typelevel-endorsed libraries. Unlike Kotlin, it gets pretty close.

~~~
KennyCason
I mean, if you like Scala, you'll most likely like Kotlin, there are a LOT of
similarities between the two.

------
kinkdr
Started learning Haskell just a couple of weeks ago. My only complaint with
the language so far is that I cannot have the same name for a field in two
records in the same module.

Other than that it is amazing the confidence it gives me; if it compiles it
works (r).

~~~
harpocrates
If you are using GHC, the newest version (8.0.1) actually supports duplicate
record fields with the
[DuplicateRecordFields]([https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#duplicate-
record-fields)) extension. Check it out!

~~~
pyrale
Nice ! Does it work well with lenses ?

~~~
rfergie
So you can do something like this:

    
    
        data Foo = Foo { _bar :: String }
        data Buzz = Buzz {_bar :: String}
    

And derive lenses? I think it doesn't - this is more than just a duplicate
record name, you also end up with a duplicate `bar` lens

------
krautsourced
This may sound (and probably is) quite superficial, but I am immediately put
off by any language that uses syntax like this: foldr' (+) :: Num t1 => t1 ->
[t1] -> t1 Why? Because of things like => and -> are just a pain to write all
the time and make you chase all over the keyboard, even more so on non-english
keyboards. Just my very personal preference of course, but still...

~~~
dancek
It is quite superficial. Code being easy to read is much more important than
code being easy to write. I'm not saying it's a bad idea to have both, but
look at Java or C# that are a pain to write without a very smart IDE (just
because of the amount of boilerplate). Even they have been saved by tooling.

Also, modern popular languages tend to use arrows (Java, C#, ES6). Not to say
that popularity matters, but people are used to it nowadays.

------
lifeisstillgood
How bad is it looking at the examples and thinking "I love that lambda symbol
as a prompt. I want"

I have to revisit my base setup soon. The 1990s wants its bash_profile back

------
jjawssd
How difficult is it in your experience for developers to learn Haskell while
on the job?

~~~
evincarofautumn
I basically learned Haskell at my first job (writing a compiler), and it was
pretty easy to productively contribute starting on day 1, especially because
there seems to be less risk of breakage than in many other languages. I also
helped teach it at the next job, and developers found it pretty easy to pick
up, just different from what they were used to.

Prior to this, I had some experience using it for hobby projects, but there
was a lot more to learn for real-world use. My colleagues and I helped each
other learn new concepts and write better code, as best we could, but we did
end up making some questionable design decisions. I think you still need an
experienced Haskeller to advise on good program architecture.

~~~
andrewchambers
Compilers are a bit easier to start with because you can just deal with pure
functions for the majority of the time

~~~
evincarofautumn
You _can_ , but that’s not to say we _did_ , haha. One of the aforementioned
questionable design decisions.

------
NotThe1Pct
I tried haskell queues a while ago - under the advice of a friend and compared
with a straightforward C++ queue - it was about 100x slower. Abandoned the
idea.

~~~
bbcbasic
Let me guess ... you used [a]

~~~
sammoth
What are you implying? What should they have used?

~~~
tome
The list datatype is horrendously unsuited for being used a queue. They should
have used a datatype designed for use as a queue.

------
xamuel
I taught myself Haskell because people say it improves you as a programmer. I
didn't see that, but I have a math PhD so maybe I'm just too familiar with
abstract types to gain new insight from Haskell.

As a language, it's sterile. You can tell it was designed by committee.

~~~
the_af
> _As a language, it 's sterile. You can tell it was designed by committee._

This remark is puzzling. How do you tell if a language is sterile?

~~~
xamuel
Hard to put a finger on it but it lacks a certain "playfulness" which real-
world languages have.

It's like the difference between Lojban/Esperanto (artificially constructed
spoken languages) and English/Spanish. English/Spanish are "imperfect" but
their warts are the results of thousands of years of culture (and may not be
imperfections after all, they may be a case of some kind of coding theory
emerging organically)

~~~
feanaro
That's surprising since "playful" is exactly how I would experience how I
perceive Haskell. I guess it only goes to show how worthless subjective
impressions usually are.

In any case, I think suggesting Haskell isn't a "real-world" language comes of
a bit trollish, even though you probably didn't mean it like that.

