在hakell中“两个”类型构造函数的用途是什么

时间:2019-07-07 09:33:16

标签: haskell

在研究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

我想知道为什么不删除LeftRight的值构造函数。该代码仍然可以正常工作,同时仍然能够打印出我们想要的值。

1 个答案:

答案 0 :(得分:7)

Eithertagged union [wiki]。这意味着它可以从(在这种情况下)两种类型获取值。例如,如果Code不是字符串,则您的函数将需要某种求和类型。否则它将如何传达CodeString?因此,Either例如用于一个列表,其中可以包含IntString[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 Val2some_computation_that_can_fail2 :: Val2 -> Either Err Val3some_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,依此类推。