Created
November 13, 2015 03:18
-
-
Save enolan/8bdc5c80a7628dad048c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Haskell: The Bad Parts | |
Complaining about a tiny program, armchair language design | |
What's the program? Pia-forward | |
A utility for setting up port forwarding on the Private Internet Access VPN service | |
- 103 lines | |
- Mostly IO | |
- Deals with exceptions | |
- JSON | |
- web service API | |
Let's take a closer look at what it does: | |
https://www.privateinternetaccess.com/forum/discussion/180/port-forwarding-without-the-application-advanced-users | |
Let's look at the code | |
- cabal file | |
- 15 dependencies of which 7 aren't bundled and 1 is unneccesary | |
- not very batteries included arguably 4 of the nonbundled ones should be | |
- 6 language extensions | |
- this sort of thing is extremely common, so everyone is using slightly | |
different versions of the language - the standardization process is very | |
slow and conservative. | |
- Main.hs | |
- 25 lines of imports - I'm sure this is really *bad* but it's not what you | |
were looking for when you opened the file | |
- line 32: newManager - it's responsible for pipelining and proxying and | |
general settings related to HTTP connections. | |
- You're strongly encouraged to only ever use one, but you have the | |
opportunity to mess up each time you call something that uses a manager. | |
It's just one more thing to keep track of. In a language with extensible | |
effects like Idris, you'd create a Manager effect and every function that | |
made HTTP requests would require that effect. You'd never name the | |
manager as a variable, and accidentally using two different managers | |
would be much harder. | |
Extensible effects are possible in Haskell, but the type hackery is much | |
more complicated, at least at first glance. | |
- line 34: Exceptions! try's type is try :: Exception e => IO a -> IO (Either e a) | |
it catches exception of a particular type, which is determined by inference | |
or annotation. It's a little weird, but whatever. | |
- What's worse is the constant tension between exceptions, which are | |
unchecked and explicit failure notification. Exceptions bubble, which is | |
often convienient while Maybe/Either can but don't automatically. If you | |
want Maybe/Either to bubble you need to use monads, and if you're already | |
in a monad you need to use transformers which can get confusing fast. | |
Another case where you'd like extensible effects. | |
- line 43: named field puns. This extension is easy for me, but it's fairly | |
common to be working in someone else's codebase and get confused because | |
they're using an extension you're unfamiliar with. | |
- line 44: exceptions again. A bit weird. ScopedTypeVariables in play here. | |
it's also used above. Show type of catches. | |
- line 54: OverloadedStrings. Way too many ways to use strings. String, | |
ByteString, Lazy ByteString, Text, Lazy Text. | |
- line 64: Can't actually complain about this, I just did it in an | |
overcomplicated way. | |
- line 67-68: Too many strings again. | |
- line 69: most nitpicky part. Sleep is threadDelay because of reasons you | |
don't usually care about when you use it. | |
- rest is pretty much fine. Can complain about there being too many strings | |
some more if we really want. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment