#blog https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ ## なぜこのブログを読んだか 度々話題に上がったりもしてたのと軽く読んだことはあったし、 [[Designing With Types]] や [[Domain Modeling Made Functional]] などを通して考え方は理解していたつもりだったが改めて腰を据えて読んでみた ## メモ ### 前提 ```haskell head :: [a] -> a ``` このような関数を実装することは一見簡単なように見えるが実は `[]` (empty list) の場合の実装を提供できないためこのまま実装することはできない。 ```haskell head :: [a] -> Maybe a ``` もちろん上記のように `Maybe` やら Java などでいえば `Optional` や `nullable` にすることで実装することは可能になる。 一方で利用する際には、幾度となく `Maybe` のケアをする必要が出てきてしまうという課題を利用側に残すことになる。 ```haskell head :: [a] -> a ``` 改めてにはなるが、この関数を実装するアプローチは今紹介した return type の制約を弱くするだけではなく、 arg の制約を強くすることでも達成できる。 ```haskell data NonEmpty a = a :| [a] head :: NonEmpty a -> a ``` このように `NonEmpty` という `[]` である可能性を排除した型を作ってしまえば (より制約を強めれば)、 `[]` の実装は不要になり関数としては実装可能になる。 ### Parse over Validate ```haskell validateNonEmpty :: [a] -> IO () validateNonEmpty (_:_) = pure () validateNonEmpty [] = throwIO $ userError "list cannot be empty" parseNonEmpty :: [a] -> IO (NonEmpty a) parseNonEmpty (x:xs) = pure (x:|xs) parseNonEmpty [] = throwIO $ userError "list cannot be empty" ``` このブログの中では、 `validate` というのは `check` に近い感覚で使用していて、入力を `check` するだけを指している。 一方で `parse` は、入力を `check` した上でより綺麗になったデータを return type として下流に流す役割を指していると認識した。 上記の例で言えば、 `IO (NonEmpty a)` というように `NonEmpty a` という綺麗になったデータが return されるため caller はその後 empty のチェックをする必要がない `validate` を利用すると必ずコードの様々な箇所や様々な層で値をチェックするコードが増えてしまいいわゆる `shotgub parsing` が横行すると指摘している。 ## 感想 改めて、全面的に同意する考え方だなと感じた。 また [Always Valid Domain Model](https://scrapbox.io/kawasima/Always-Valid_Domain_Model) にも通じるものがありそちらも改めて読んでみたいと感じた。