Haskell: treat newtype as String



我经常有这个简单的模式:

newtype Username = Username Text

目的当然是在操作"用户名"时提高安全性,而不是将其与其他字段混合。 但是,一直打包和拆包变得乏味。 我想知道是否有技巧可以将"用户名"视为字符串(例如AsString或OverloadStrings),还是它违背了目的?

我认为你的newtype方法很好。你必须问问自己,为什么你总是需要打包和拆包。对于这样的类型,通常应该有一个定义它的模块、一堆繁琐的 typeclass 实例和一些操作函数。你只是把它砸出来。

{-# language GeneralizedNewtypeDeriving #-}
module MyNamespace.Username (.....) where
import Data.Hashable
newtype Username = Username Text
deriving (Eq, Ord, Show, Hashable)
unUsername :: Username -> Text
validateForm :: Text -> Maybe Username

我认为它违背了目的。理想情况下,您应该只将其打包在输入站点中(例如,在您的 web API 中,通常隐式使用FromJSONFromHTTPApiData之类的东西)并且仅在使用前解压缩(例如,在查询另一个 Web API 时,通过ToJSON隐式,或者在查询数据库时,希望再次隐式使用某种机制,允许您将Username"直接"存储在数据库中 - 例如EntityField持久)

如果你想要正确的类型安全,你应该使用newtype.这旨在防止您来回隐式转换以防止意外错误。

如果您只是想要一个不妨碍您的类型别名,则应使用 type 关键字:

type Username = Text

这意味着接受Username的函数可以采用Text,而无需调用值构造函数等。事实上,String被定义为type String = [Char]因此您可以在任何需要字符串的地方提供[Char];它们是等效的。(巧合的是,将链表用于字符串而不是向量的效率低下是TextByteString存在的原因。

您仍然需要转换才能使其成为String,但是使用这种方法,除了阅读代码的人的语义提示外,UsernameText类型之间没有区别。

如果你想在String之间转换,我对这些语言扩展不太熟悉,但只要你还使用type别名而不是newtype定义,它们看起来就可以了。

最新更新