在研究haskell的类型系统时,我遇到了一个名为“ Either”的类型构造函数。一个用例是
下的代码import qualified Data.Map as Map
data LockerState = Taken | Free deriving (Show, Eq)
type Code = String
type LockerMap = Map.Map Int (LockerState, Code)
lockerLookup :: Int -> LockerMap -> Either String Code
lockerLookup lockerNumber map =
case Map.lookup lockerNumber map of
Nothing -> Left $ "Locker number "
++ show lockerNumber ++ " doesn't exist!"
Just (state, code) -> if state /= Taken
then Right code
else Left $ "Locker " ++ show lockerNumber
++ " is already taken!"
lockers :: LockerMap
lockers = Map.fromList
[(100,(Taken,"ZD39I"))
,(101,(Free,"JAH3I"))
,(103,(Free,"IQSA9"))
,(105,(Free,"QOTSA"))
,(109,(Taken,"893JJ"))
,(110,(Taken,"99292"))
]
带有示例函数调用:
> lockerLookup 101 lockers
我想知道为什么不删除Left
和Right
的值构造函数。该代码仍然可以正常工作,同时仍然能够打印出我们想要的值。
答案 0 :(得分:7)
Either
是tagged union [wiki]。这意味着它可以从(在这种情况下)两种类型获取值。例如,如果Code
不是字符串,则您的函数将需要某种求和类型。否则它将如何传达Code
或String
?因此,Either
例如用于一个列表,其中可以包含Int
和String
:[Either Int String]
。
Either
通常用于封装可能失败的计算。然后Left
构造函数存储错误消息/异常参数,而Right
数据构造函数存储成功计算的结果。
此逻辑实际上是在instance Monad Either
[src]中编码的:
instance Monad (Either e) where Left l >>= _ = Left l Right r >>= k = k r
所以在这里我们可以定义一个像这样的计算
some_computation :: Val1 -> Either Err Val4
some_computation v1 = do
v2 <- some_computation_that_can_fail1 v1
v3 <- some_computation_that_can_fail1 v2
some_computation_that_can_fail v2 v3
在这个假设的示例中,函数的类型为some_computation_that_can_fail1 :: Val1 -> Either Err Val2
,some_computation_that_can_fail2 :: Val2 -> Either Err Val3
和some_computation_that_can_fail1 :: Val2 -> Val3 -> Either Err Val4
。
如果some_computation_that_can_fail1 v1
返回Left err
,则some_computation v1
将返回该Left err
。另一方面,如果返回Right result
,则v2
将访问该结果,因此您可以进一步处理result
中的some_computation_that_can_fail2 v2
,依此类推。