@@ -24,15 +24,16 @@ popular on Twitter --- "heresies", if you may permit the terminology.
2424
2525[ Five-Point Haskell ] : https://blog.jle.im/entries/series/+five-point-haskell.html
2626
27- Let's jump right into point 1: the doctrine of ** Total Depravity** .
27+ Let's jump right into point 1: the doctrine of ** Total Depravity** , and why
28+ Haskell is perfectly primed to make living with it as frictionless as possible.
2829
2930> Total Depravity: If your code's correctness depends on keeping complicated
3031> interconnected structure in your head, a devastating incident is not a matter
3132> of _ if_ but _ when_ .
3233>
33- > Therefore, delegate these concerns to the compiler and tooling, express
34- > conditions in your types, and free yourself to only mentally track the actual
35- > important things.
34+ > Therefore, delegate these concerns to tooling and a sufficiently powerful
35+ > compiler, use types to guard against errors , and free yourself to only
36+ > mentally track the actual important things.
3637
3738Mix-ups Will Happen
3839-------------------
@@ -55,6 +56,9 @@ This is the myth of the hero programmer. Did you have a bug? Well, you just
5556need to upgrade your mental awareness and your context window. You just need to
5657be better and better at keeping more in your mind.
5758
59+ Admittedly, actually _ addressing_ these issues in most languages requires a lot
60+ of overhead and clunkiness. But luckily we're in Haskell!
61+
5862### ID Mix-ups
5963
6064The [ 2022 Atlassian Outage] [ atlassian ] , fundamentally, was the result of
@@ -110,18 +114,61 @@ Knowing this can happen, we can add a simple newtype wrapper so that
110114accidentally using the wrong ID is a compile error:
111115
112116``` haskell
113- newtype SiteId = SiteId Id
114- newtype AppId = AppId Id
117+ newtype SiteId = SiteId String
118+ newtype AppId = AppId String
119+
120+ instance ToJSON SiteId where
121+ toJSON (SiteId x) = object [ " type" .= " Site" , id " .= x ]
122+
123+ instance FromJSON SiteId where
124+ parseJSON = withObject " Id " $ \v ->
125+ tag <- v .: " type "
126+ unless (tag == " Site " ) $
127+ fail " Parsed wrong type of ID ! "
128+ SiteId <$> (v .: " id " )
129+
130+ instance ToJSON AppId where
131+ toJSON (AppId x) = object [ " type " .= " App " , id" .= x ]
132+
133+ instance FromJSON AppId where
134+ parseJSON = withObject " Id" $ \ v ->
135+ tag <- v .: " type"
136+ unless (tag == " App" ) $
137+ fail " Parsed wrong type of ID!"
138+ AppId <$> (v .: " id" )
115139```
116140
117141And now such a mis-call will never compile! Congratulations!
118142
119143We did have a downside now: we can no longer write code polymorphic over Id's
120144when we want to. In the untyped situation, we could _ only_ write polymorphic
121- code, and in the new situation we can _only_ write code for one Id type . In
122- some cases, we would like the ability to choose to do one or the other and get
123- the best of both worlds. We can get this by using _phantom types_, types that
124- don't refer to anything inside the actual data representation:
145+ code, and in the new situation we can _ only_ write code for one Id type.
146+
147+ ``` haskell
148+ instance FromJSON SiteId where
149+ parseJSON = withObject " Id" $ \ v ->
150+ tag <- v .: " type"
151+ unless (tag == " Site" ) $
152+ fail " Parsed wrong type of ID!"
153+ SiteId <$> (v .: " id" )
154+
155+ instance ToJSON SiteId where
156+ toJSON (SiteId x) = object [ " type" .= " Site" , id " .= x ]
157+
158+ instance FromJSON AppId where
159+ parseJSON = withObject " Id " $ \v ->
160+ tag <- v .: " type "
161+ unless (tag == " App " ) $
162+ fail " Parsed wrong type of ID ! "
163+ AppId <$> (v .: " id " )
164+
165+ instance ToJSON AppId where
166+ toJSON (AppId x) = object [ " type " .= " App " , id" .= x ]
167+ ```
168+
169+ However, luckily, because we're in Haskell, it's easy to get the best of both
170+ worlds with _ phantom types_ (that don't refer to anything inside the actual
171+ data representation):
125172
126173``` haskell
127174data Id a = Id { getId :: String }
@@ -657,7 +704,40 @@ flawed abstractions, you can actually think about your business logic, the flow
657704of your program, and architecting that castle of beauty I know you are capable
658705of.
659706
660- Tune in next time as we discuss the next principle of [ Five-Point
707+ ### The LLM Elephant
708+
709+ Okay, let's address the elephant in the room. We're writing this in 2026, in
710+ the middle of one of the biggest revolutions in software engineering in the
711+ history of the field. How relevant will these issues be in the age of LLMs and
712+ agentic coding?
713+
714+ I don't have too much to say here, except that the fundamental issue being
715+ addressed here exists both in LLMs and humans: the limited "context window" and
716+ attention. Humans might be barely able to keep a dozen things in our heads,
717+ LLMs might be able to keep a dozen dozen things, but it will still be
718+ fundamentally finite. So, the more we can move concerns out of our context
719+ window (be it biological or computational), the less crowded our context
720+ windows will be, and the more productive we will be.
721+
722+ I'm not sure how quickly LLM-based agentic coding will progress, but I am sure
723+ that the accidental "dropping" of concerns will continue to be a bottleneck. If
724+ anything, it might be _ the_ bottleneck. If we can provide LLMs with properly
725+ "depravity-aware" typed code --- or somehow encourage them to write it by
726+ giving them the right iterative tooling --- I (maybe naively) believe this
727+ might be the key to unlocking the full potential of agentic coding.
728+
729+ ### The Next Step
730+
731+ Total depravity is all about using types to _ prevent errors_ . However, most
732+ discussions about the power of types stop here. Oh, how boring types would be
733+ if this was all they gave us!
734+
735+ Types are also a power tool for _ program design_ , helping you guide the
736+ creation of your abstractions and pushing you to more expressive and robust
737+ designs. They aren't just for preventing bad code, they're for opening your
738+ mind to new avenues of design that were impossible before.
739+
740+ Let's explore this further in the next principle of [ Five-Point
661741Haskell] [ Five-Point Haskell ] , ** Unconditional Election** !
662742
663743Special Thanks
0 commit comments