Mark Karpov
markkarpov.com · Personal blog · on HN since 2017
Mark Karpov, a Haskell developer and author of Megaparsec, writes tutorials and opinion pieces on Haskell, OCaml and functional programming.
What HN saysCommenters link his tutorials, like the one on GHC generics, as references for functional programming techniques and cite his Haskell versus OCaml comparison.
26HN people shared it
14linked it in comments
14stories submitted
417story points
1 year agolast shared
2017people per year2026
Most-shared posts
- 1Lisp and Haskell (2017)4 people · 310 points · first shared 2018 · 166 comments on HN
- 2Haskell vs. OCaml4 people · 13 points · first shared 2019 · 1 comments on HN
- 3Migrating text metrics to pure Haskell4 people · 3 points · first shared 2017 · discussion on HN
- 4Megaparsec Tutorial3 people · 52 points · first shared 2020 · 9 comments on HN
- 5Haskell: Smart constructors that cannot fail2 people · 7 points · first shared 2018 · discussion on HN
- 6Haskell GHC Generics Explained2 people · 4 points · first shared 2020 · discussion on HN
- 7Free monad considered harmful2 people · 1 points · first shared 2018 · discussion on HN
- 8Ghc optimization and fusion2 people · first shared 2020
- 9Category Theory Basics, Part I (2016)1 people · 24 points · first shared 2019 · discussion on HN
- 10Haskell Exceptions Tutorial1 people · 3 points · first shared 2019 · discussion on HN
- 11Parsing simple imperative language1 people · first shared 2018
- 12Exceptions1 people · first shared 2023
- 13Learn haskell1 people · first shared 2020
What HN people wrote when they linked it
random314 · 2020-05-01
You are not capable of writing a PhD chapter. You lack the basic scientific thinking or method required. I suggest you focus on your core competency - chuckling.
Here is some basic reading material for you. Lets see if you can follow this
https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurren…
do a1 <- async (getURL url1)
a2 <- async (getURL url2)
page1 <- wait a1
page2 <- wait a2
This implements async await in Haskell via a library using Monads. Hint: you cannot do this in C via any library. You need to modify the language. If you are uneducated about Monads, you might think this is similar to some kind of C code. It is not!
Here is the same do syntax being used to parse source files instead of doing async/await IO. Yes this parser will also perform backtracking etc, which will not be obvious to anyone who thinks this is some kind of transliteraton of C
https://markkarpov.com/tutorial/megaparsec.html
mySequence :: Parser (Char, Char, Char)
mySequence = do
a <- char 'a'
b <- char 'b'
c <- char 'c'
return (a, b, c)
Hint: If you want to do something like this in C, you use yacc/bison, a parser generator tool - there is no library. And it is fucking ugly.
Hint 2: There are monads for parsing, async IO, exceptions, nondetermenism, monte carlo .........
Hint 3: The parser libraries are 25 years old.
Hint 4: Monad libraries represent less than 1% of PL research over the last 40 years.
Hint 5: C# LINQ is…
gus_massa · 2017-06-26
I like the article, but I don't agree with the conclusion.
> When profiling, it is important to always run your code over an extended period of time, preferably seconds, in order to smooth out any irregularities that may occur.
I agree. Moreover, for very small differences (1%-5%) I prefer that the benchmark is long enough that the difference is at least 200ms, or preferably 1 second.
> When running extremely short pieces of code, in this case, around 500 nanoseconds (The original measurements did not have units, this is an educated guess).
I looked at the other article https://markkarpov.com/post/migrating-text-metrics.html . The graph of the times don't look like the graph of a benchmark of 500ns~=1us. They are too clean, a graph of a measurement of a few ms is very noisy, lots of crazy values that make the results impossible to compare. The graphics have two nice sets of bars that are apparently following a smooth curve (not drawn in the graph). So it was definitively not a measurement of a few .5us. He was repeating it many times to get a long enough time.
> In my benchmarks, I’ve made the C code and the Haskell code run on inputs of 100 thousand, 1 million, and 10 million long strings to get some reliable measurements. Each measurement is done 1000 times to make sure we can obtain some decent results.
For comparison, the original article uses strings of length 8--160, i.e. 1000 times smaller. So he is now changing the benchmark. Perhaps Haskell has a sweet spot…
mrkeen · 2025-08-15
No idea how common it is. It's never been my main work language but I've been using it at work for prototyping/scripting/automation/analysis etc for at least ten years now.
It looks like what I've done is most similar to https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html
And I think this was the post that proposed tagless-final over free-monads: https://markkarpov.com/post/free-monad-considered-harmful.html
ReleaseCandidat · 2023-11-12
I don't like Exceptions in OCaml (or Haskell or C++ or JS/TS) either. But they aren't unsafe, except for bugs in the compiler/runtime (in OCaml, in C++ there are of course some footguns ;).
Of course they add "bottom" to any function where an Exceptions can occur (and other things, see for example
https://markkarpov.com/tutorial/Exceptions) but for stuff like `0/0` there are 3 possibilities:
use something like `Maybe` for the result - clumsy.
return (for example) 0, which is what most theorem provers (like Coq or Lean and dependently typed languages like Idris) do, that need their functions to be total
or throw an exception.
Now, with OCaml's effect systém, there also is no need to use exceptions for control flow - which you should have never done anyway.
hither_shores · 2022-09-14
> like how to use FP to solve expression problem
Some common approaches:
- Tagless final style: https://okmij.org/ftp/tagless-final/
- Datatype-generic programming: https://markkarpov.com/tutorial/generics.html
- Polymorphic records and variants: https://www.cl.cam.ac.uk/teaching/1415/L28/rows.pdf
massysett · 2022-07-07
These days megaparsec might be a better way to get started as it has built on Parsec to improve the speed and documentation.
https://markkarpov.com/tutorial/megaparsec.html
https://hackage.haskell.org/package/megaparsec
However it does rely on some GHC extensions, which makes things a bit more complicated for beginners, so for simplicity's sake it might be easier to start with Parsec and one of the old papers that goes with it.
ghostwriter · 2021-12-21
Laziness on itself does not prevent one from properly evaluating resource utilisation. In fact, laziness helps in resource preservation. But what makes it less predictable is various optimisation techniques that come to aid the lazy environment: strictness analysis, rewrite rules, and stream fusion[1][2]. They may change significantly between compiler releases and affect the previously optimised codebase.
[1] https://wiki.haskell.org/GHC_optimisations
[2] https://markkarpov.com/tutorial/ghc-optimization-and-fusion.html
reikonomusha · 2020-08-03
GHC does have special support for fusion and rewriting. See e.g. [1]. The laziness comes with the language, but turning it efficient requires a series of these rewrite rules expressed as GHC-specific metadata.
[1] https://markkarpov.com/tutorial/ghc-optimization-and-fusion.html#rewri…
pas · 2018-07-12
Some people just don't like parentheses. And they hate the Paamayim Nekudotayim (PHP PTSD?) And really like that the compiler helps them (types), so they are left with Scala.
https://markkarpov.com/post/lisp-and-haskell.html
kccqzy · 2018-05-21
Wow I didn't realize Haskell beginners would learn to use Trifecta. Megaparsec is much more beginner friendly (and expert-friendly too). It has tutorials that guide you gently through the process of writing a parser. See https://markkarpov.com/megaparsec/parsing-simple-imperative-language.h…
danidiaz · 2017-06-14
There was a recent post about "imperative Haskell": http://vaibhavsagar.com/blog/2017/05/29/imperative-haskell/
The code in this other post about implementing string distance metrics is also quite imperative: https://markkarpov.com/post/migrating-text-metrics.html
pathsjs · 2017-06-14
Well, these are mutable, but only in the ST or IO monad - which is a guarantee, but at the same time it is not quite the same thing. You cannot just accumulate state by mutating some stuff, then in a separate part of the program mutate it again.
Which is intentional, of course, but quite opposite to the imperative mindset.
About {#- Language Strict #-}, thank you - I was not aware of it.
I think the first example in this post https://markkarpov.com/post/migrating-text-metrics.html makes it clear that, while one can program in imperative style, it is not at all natural, and it is going to introduce as much boilerplate as, say, trying to program in functional style in Java 6
nextaccountic · 2021-12-14
What means D < U in your notation? It's like, D is a subset of U?
Anyway the problem with trying to make a function total by fiat like with the definition (D, R, f) is that for some functions (even computable functions), its domain may be an uncomputable set.
That's because if we could decide if a given x in f(x) makes f return something or not, if f represents the output of a Turing machine we could use that to solve the halting problem.
So while in principle every function is total in some domain D (precisely the domain which it is defined to return some value), sometimes we can't talk very usefully about this domain. In this case, we choose to treat f as a partial function and talk about a larger set of values D' f receive as input (and might or might not return anything), for which D is a subset.
Some properties might not be literally undecidable but we may not know how to solve them yet. For example, the function collatz : Nat -> () [0] that receives a natural number and either return nothing if its collatz sequence[1] eventually reaches 1, or else run forever. What's the domain of this function? (you can switch this for any actually undecidable problem for extra hardness)
Unfortunately the linked article doesn't talk about this particular motivation for defining partial functions in computer science, and instead cites sqrt as an example, even though it has a perfectly computable domain. The domain of sqrt is just the non-negative reals; which we could give a more…
Eugeleo · 2020-02-09
Not the OC and (mostly) not related to Haskell performance, but the following could be useful to you:
State of Haskell Ecosystem: https://github.com/Gabriel439/post-rfc/blob/master/sotu.md#compilers
Guide to Haskell (2018): https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-…
Haskell learner milestones: https://stackoverflow.com/a/1016986
GHC optimizations (rather advanced, but interesting): https://stackoverflow.com/questions/12653787/what-optimizations-can-gh…
Compilation of various Haskell tutorials on more advanced topics: https://markkarpov.com/learn-haskell.html
Despite the popular saying, there’s a wealth of knowledge about Haskell beyond just academic papers, and in digestable form, but it’s scattered around little-known blogs. I’d recommend you to check out r/haskell from time to time, or subscribe to the Haskell newsletter - at least for me, those are the places where I got to know most of Haskell blogs.