Haskell 中的简单优化类型

Simple Refinement Types in Haskell

根据 Scott Wlaschin 的 blog post and Book "Domain Modeling made Functional", and from Alexis King's post,我认为域模型应该编码尽可能多的关于域的信息,就像在类型中实际可行的那样,以便“使非法状态无法表示”并获得强有力的保证允许我编写完整的域逻辑函数。

在基本的企业应用中,我们有很多基本的域类型,如街道名称、公司名称、城市等。为了以一种可以防止以后出现大多数错误的形式来表示它们,我想使用一种可以让我

我可以想到两种实现此类类型的方法:作为具有智能构造函数和隐藏数据构造函数的自定义抽象数据类型,或者通过某种类型级机制(我模糊地阅读了有关细化类型的内容?可以通过以下方式表示此类类型一些较新的语言扩展?通过 LiquidHaskell?)。哪种方法是明智的?哪种方法最容易适用于在常规 Text 上运行的所有函数,以及我如何最容易地组合两个或多个相同细化类型的值、映射它们等?

理想情况下,会有一个库可以帮助我创建此类自定义类型。有吗?

根据 Alexis King 的博客,我认为合适的解决方案如下所示。当然,其他解决方案也是可行的。

import Control.Monad (>=>)

newtype StreetName = StreetName {getStreetName :: String}

-- compose all validations and wrap them in new constructor.
asStreetName :: String -> Maybe StreetName
asStreetName = StreetName <$> rightNumberOfChars >=> rightCharSubset >=> noTrailingWhiteSpace

-- This funcs will process the string, and produce another validated string or nothing. 
rightNumberOfChars :: String -> Maybe String
rightNumberOfChars s = {- ... -}

rightCharSubset :: String -> Maybe String
rightCharSubset s = {- ... -}

noTrailingWhiteSpace :: String -> Maybe String
noTrailingWhiteSpaces = {- ... -}

main = do
  street <- readStreetAsString
  case asStreetName street of
    Just s  -> {- s is now validated -}
    Nothing -> {- handle the error -}

使 StreetName 成为一个隐藏的构造函数,就像使用 asStreetName 作为一个智能构造函数一样。请记住,其他函数应在类型中使用 StreetName 而不是 String,以确保数据经过验证。