2013-07-31 15 views
4

我是Haskell的新手,我只是遵循RWH上的示例。我有在第14章有以下程序問題:Haskell monad鏈接中的類型檢查錯誤

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 

看來,在單子寫findCarrierBillingAddres當鏈接的格式使用>> =,它只是不類型檢查:

/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. 

問題是......爲什麼使用>> =的第二個格式不會輸入check?

+0

你應該把人的最後一個參數。部分應用似乎更好。你可以使用Kleisli組合重寫,<= <。 – augustss

回答

8

這只是單態的限制又出毛病了。由於您有一個沒有類型簽名的模式綁定,因此推斷的類型是單形的,因此由第一次使用確定。

它只是改變

lookup m k = flip M.lookup m k 

甚至

lookup m = flip M.lookup m 

你只需要說服GHC來概括它時,它只是一個簡單的模式綁定不會做的功能。添加一個參數會將它變成一個函數綁定,這意味着它將被完全泛化。

如果我失去你有點起來了,我已經blogged about this

+0

+1博文 –

+0

@jk。我很高興你喜歡它:) – jozefg

+0

非常感謝。正是這種情況:) – kkspeed

7

你被打與Monomorphism Restriction 當類型inferencer試圖推導出當地 lookup函數的類型。

而不是演繹最普通的類型,它的lookup第一次使用 ,它應該有類型lookup :: Map [Char] [Char] -> [Char] -> Maybe [Char],不能統一時,你再嘗試使用它 上的Map [Char] MobileCarrier值決定。

您的第一個選擇是使用編注 {-# 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