2017-02-23 39 views
0

如何使用綁定& fmap編寫函數事務而不用標記?如何用bind&fmap編寫這段代碼?

transaction :: UTCTime -> EncUser -> STM (Either Text()) 
    transaction now user = do 
     dbData <- readTVar db 
     case isValidRequest dbData of 
     Right _ -> do confirmRegistration user 
         return $ Right() 
     Left err -> return $ Left err 
     where isValidRequest = registrationExists >=> isConfirmationValid now 

    confirmRegistration :: EncUser -> STM() 
    registrationExists :: DbData -> Either Text Registration 
    isConfirmationValid :: UTCTime -> Registration -> Either Text Registration 

我的嘗試是沿着這些線路:

transaction :: UTCTime -> EncUser -> STM (Either Text()) 
    transaction now user = do 
     readTVar db 
     >>= return . isValidRequest 
     >>= fmap (confirmRegistration user) 
     where isValidRequest = registrationExists >=> isConfirmationValid now 

...但編譯失敗,錯誤波紋管,我似乎無法理解如何FMAP confirmRegistration上無論結果的頂部通過isValidRequest

• Couldn't match type ‘Either Text’ with ‘STM’ 
    Expected type: Either Text Registration -> STM (Either Text()) 
    Actual type: STM Registration -> STM (Either Text()) 
• In the second argument of ‘(>>=)’, namely 
    ‘fmap (confirmRegistration user)’ 
    In the expression: 
    do { readTVar db } >>= return . isValidRequest 
    >>= fmap (confirmRegistration user) 
    In an equation for ‘transaction’: 
     transaction now user 
     = do { readTVar db } >>= return . isValidRequest 
      >>= fmap (confirmRegistration user) 
     where 
      isValidRequest = registrationExists >=> isConfirmationValid now 

回答

2

doñ產生浮選是相當機械:

transaction now user = 
    readTVar db >>= \dbData -> 
    case isValidRequest dbData of 
    Right _ -> confirmRegistration user >> 
       return (Right()) 
    Left err -> return $ Left err 
    where isValidRequest = registrationExists >=> isConfirmationValid now 
+0

上面的case-of表達式與Either的fmap實現非常相似,所以這就是爲什麼我想用fmap代替case的 – vidi

+0

@vidi你不能,因爲你有'confirmRegistration user >>'在那裏。沒有它,你可以像這樣提取'return':return(fmap(const())(isValidRequest dbData)返回(case isValidRequest dbData Right_-> Right(); Left err-> Left err) )'。但那不是你所擁有的。 – melpomene

+0

現在我意識到confirmRegistration的類型在這裏是錯誤的。我會修復類型並回來。謝謝。與此同時,你是對的,給出原始問題中的類型 – vidi

0

這是最後的代碼後,我固定類型confirmRegistration,從墨爾波墨涅的意見後。我將此作爲參考發佈,因爲它看起來非常接近我想要的東西。

transaction :: UTCTime -> Text -> EncUser -> STM (Either Text()) 
transaction now rid user = do 
    readTVar db 
    >>= sequence . confirmRegistration user <.> isValidRequest 
    where isValidRequest = findRegistration rid >=> isConfirmationValid now 

confirmRegistration :: EncUser -> Registration -> STM() 
findRegistration :: Text -> DbData -> Either Text Registration 
isConfirmationValid :: UTCTime -> Registration -> Either Text Registration 

注:運營商<>是「函子組成」發現here

我依然缺少直覺爲什麼序列需要有但我可能應該張貼,作爲一個不同的問題。