kks*_*eed 4 monads haskell map
我是Haskell的新手,我只是关注RWH的例子.我在第14章遇到以下程序的问题:
import qualified Data.Map as M
type PersonName = String
type PhoneNumber = String
type BillingAddress = String
data MobileCarrier = Honest_Bobs_Phone_Network
| Morrisas_Marvelous_Mobiles
| Petes_Plutocratic_Phones
deriving (Eq, Ord)
findCarrierBillingAddress :: PersonName
-> M.Map PersonName PhoneNumber
-> M.Map PhoneNumber MobileCarrier
-> M.Map MobileCarrier BillingAddress
-> Maybe BillingAddress
-- This will work
findCarrierBillingAddress person phoneMap carrierMap addressMap = do
phone <- M.lookup person phoneMap
carrier <- M.lookup phone carrierMap
address <- M.lookup carrier addressMap
return address
-- This will NOT work:
findCarrierBillingAddress person phoneMap carrierMap addressMap =
return person >>=
lookup phoneMap >>=
lookup carrierMap >>=
lookup addressMap
where lookup = flip M.lookup
Run Code Online (Sandbox Code Playgroud)
似乎在使用>> =以monad链接格式编写findCarrierBillingAddres时,它只是不键入check:
/home/bruce/Programming/haskell/real/ch14/hello.hs:21:9:
Couldn't match type `[Char]' with `MobileCarrier'
Expected type: MobileCarrier -> Maybe BillingAddress
Actual type: PersonName -> Maybe BillingAddress
In the return type of a call of `lookup'
In the second argument of `(>>=)', namely `lookup addressMap'
In the expression:
return person >>= lookup phoneMap >>= lookup carrierMap
>>= lookup addressMap
/home/bruce/Programming/haskell/real/ch14/hello.hs:21:16:
Couldn't match type `MobileCarrier' with `[Char]'
Expected type: M.Map PersonName BillingAddress
Actual type: M.Map MobileCarrier BillingAddress
In the first argument of `lookup', namely `addressMap'
In the second argument of `(>>=)', namely `lookup addressMap'
In the expression:
return person >>= lookup phoneMap >>= lookup carrierMap
>>= lookup addressMap
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
问题是..为什么使用>> =的第二种格式不会进行类型检查?
这只是单态性限制再次起作用.由于您具有没有类型签名的模式绑定,因此推断类型是单态的,因此由第一次使用确定.
只需将其更改为
lookup m k = flip M.lookup m k
Run Code Online (Sandbox Code Playgroud)
甚至
lookup m = flip M.lookup m
Run Code Online (Sandbox Code Playgroud)
你只需要说服GHC推广它只是一个简单的模式绑定时不会做的功能.添加参数会将其转换为函数绑定,这意味着它将完全一般化.
如果我在那里失去了一些你,我在博客上写了这个
当类型推断器试图推导出本地函数的类型时,
您会遇到单态限制lookup
.
它不是推断出最一般的类型,而是从第一次使用它确定lookup
它应该具有类型lookup :: Map [Char] [Char] ->
[Char] -> Maybe [Char]
,当你尝试在它的值上使用它时,它不能统一Map [Char] MobileCarrier
.
您的第一个选择是使用pragma禁用单同性限制
{-# LANGUAGE NoMonomorphismRestriction #-}
.第二个选项是一个类型签名添加到lookup
为使
findCarrierBillingAddress person phoneMap carrierMap addressMap =
return person >>=
lookup phoneMap >>=
lookup carrierMap >>=
lookup addressMap
where lookup :: Ord k => M.Map k a -> k -> Maybe a
lookup = flip M.lookup
Run Code Online (Sandbox Code Playgroud)