在编写一些网页请求代码时,我注意到我并没有清楚地了解在haskell中严格打字是多少被认为是好习惯。
首先是例子:
值得注意的是,sum类型无法解决这些问题,因为无效状态总是意味着程序员错误,并且处理此问题的唯一方法是崩溃。我认为有两种方法可以解决这个问题:
Session' () ...
是没有keyFetch令牌的会话,Session' Base64 ...
是一个带有一个显然,这些方法中的任何一种都有缺点。如果没有额外的类型检查,很容易忘记一些边缘情况或错误处理数据 然而,参数化类型带来了一些相当大的可用性成本。类型别名使代码本身看起来不错,但它们不一定有助于编译器错误。将会话置于状态monad也不错,但是改变类型需要索引monad和RebindableSyntax,这看起来非常繁重。
这大致是打字版本较少的版本:
fetchKey :: Base64 -> IO PrivateKey
fetchKey = undefined
data Session = Session
{ _uid :: Base64
, _keyFetchToken :: Maybe Base64
-- ...
}
getAuthorization :: Session -> IO Auth
getAuthorization session = case session ^. keyFetchToken of
Just token -> ... (fetchKey token)
Nothing -> throw MissingKeyFetchToken -- No way to recover
提问时间:社区是否就如何应对这种轻微动态的情况达成共识?
答案 0 :(得分:1)
这里的解决方案是不依赖于您的类型,并使用不包含底部/未定义的Haskell的受限子集。
我的意思是你的类型应该准确地表示一个值是什么。例如,您的函数getAuthorization :: Session -> IO Auth
是谎言,因为它表示
∀(s :: Session), (getAuthorization s :: IO Auth)
重要的部分是fo(forall)。它告诉您每个 Session
映射到IO Auth
,这不是真的; Session
_keyFetchToken
Nothing
的{{1}}不会映射到正常的IO Auth
值。 (它们映射到_|_
,我们正在考虑将其作为我们受限制的Haskell子集的一部分)
要解决此问题,您可以更准确地将Session
建模为
data Session keyType = Session {..., _keyFetchToken :: keyType}
现在,getAuthorization :: Session Base64 -> IO Auth
不再撒谎;它将始终将Session Base64
映射到IO Auth
。现在问题是如何从Session Base64
获得Session (Maybe Base64)
。这是迫使您为Nothing
建立基本案例(恢复)的步骤。如果Nothing
总是一个不可恢复的错误,那么首先不要有Nothing
,而只是崩溃,因为没有别的事可做,因为错误无法恢复。