#+title: Parse, don't validate #+roam_key: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ - source :: [[https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/][Parse, don’t validate]] * Notes When it comes to [[file:../20210423133247-type_driven_development.org][type-driven development]], the right approach should be [[file:../20210516164014-parse_don_t_validate.org][parse, don't validate]]. [[file:../20210516164106-static_type_systems.org][Static type systems]] allow for figuring out what's possible to implement. Given the [[file:../20200708123930-haskell.org][Haskell]] type signature: #+begin_src haskell :eval never head :: [a] -> a #+end_src You can reason that this would yield a [[file:../20210516164317-partial_function.org][partial function]], because it cannot be implemented for =[]=. However, since we can't implement that type signature fully, we can adjust the signature to be: #+begin_src haskell :eval never head :: [a] -> Maybe a #+end_src indicating that the function may return nothing in certain cases. This may be suitable, but down the road it causes problems, as it forces the rest of the program to deal with a =Maybe= value. The better solution would be to return a new type, =NonEmpty=, that constrains the type of data the function can work with. #+begin_src haskell :eval never data NonEmpty a = a :| [a] head :: NonEmpty a -> a head (x:|_) = x #+end_src Through this process we have *strengthened* our type. #+begin_quote Consider: what is a [[file:../20210516164934-parser.org][parser]]? Really, a parser is just a function that consumes less-structured input and produces more-structured output. By its very nature, a parser is a partial function—some values in the domain do not correspond to any value in the range—so all parsers must have some notion of failure. Often, the input to a parser is text, but this is by no means a requirement, and parseNonEmpty is a perfectly cromulent parser: it parses lists into non-empty lists, signaling failure by terminating the program with an error message. #+end_quote Parsing with a static type system should therefore be simple: "if the parsing and processing logic go out of sync, the program will fail to even compile." - [[file:../20210516170023-shotgun_parsing.org][Shotgun parsing]] :: an [[file:../20210516170032-antipattern.org][antipattern]] whereby parsing and input-validating code is mixed with and spread across processing code—throwing a cloud of checks at the input, and hoping, without any systematic justification, that one or another would catch all the "bad" cases In practice, parsing without validation looks like focusing on [[file:../20210516170353-data_type.org][datatypes]]. Specifically: 1. Use data structures that make illegal states unrepresentable. 2. Push the burden of proof upward as far as possible, but no further. Alternatively, "write functions on the data representation you wish you had, not the data representation that you are given."