簡體   English   中英

編寫 IO 操作

[英]Compose IO Operations

嗨,我正在嘗試編寫一些 IO 包裝函數。

我當前的代碼(有效)是:

getUserHome :: IO String
getUserHome = do
    usr_id <- getRealUserID
    homeDirectory <$> getUserEntryForID usr_id

我正在尋找的是一種更方便的表示法(不使用do -keyword 的表示法)。

沒有任何單子沙拉,我只會寫

getUserHome = homeDirectory . getUserEntryForID . getRealUserID

我猜有一個替代運算符用於. 尊重Monad..? 但在我所有的搜索中,我還沒有找到它。


我試過<$>但這似乎不是我想要的:

src/Main.hs:49:21: error:
    • Couldn't match type ‘IO UserEntry’ with ‘UserEntry’
      Expected type: UserID -> UserEntry
        Actual type: UserID -> IO UserEntry
    • In the second argument of ‘(<$>)’, namely ‘getUserEntryForID’
      In the first argument of ‘(<$>)’, namely
        ‘homeDirectory <$> getUserEntryForID’
      In the expression:
        homeDirectory <$> getUserEntryForID <$> getRealUserID
   |
49 |   homeDirectory <$> getUserEntryForID  <$> getRealUserID -- usr_id

謝謝你的幫助^^

您可以使用>>= ,因為 Haskell 最終“脫糖”了do塊:

getUserHome :: IO String
getUserHome = getRealUserID >>= \usr_id -> homeDirectory <$> getUserEntryForID usr_id

這可以簡化為:

getUserHome :: IO String
getUserHome  = getRealUserID >>= fmap homeDirectory . getUserEntryForID

或者:

getUserHome :: IO String
getUserHome  = getRealUserID >>= (homeDirectory <$>) . getUserEntryForID

首先始終考慮類型:

getRealUserID     ::              IO UserId
getUserEntryForID :: UserId    -> IO UserEntry
homeDirectory     :: UserEntry ->    String

現在你可以:

  1. 應用getRealUserIDgetUserEntryForID 這直接適合

    (>>=):: ma -> (a -> mb ) -> mb (>>=):: IO UserId -> (UserId -> IO UserEntry) -> IO UserEntry

    實際上,如果您希望它看起來像合成鏈,我更喜歡翻轉版本,即

    getUserEntryForID =<< getRealUserID:: IO UserEntry
  2. homeDirectory應用於此。 在您的情況下,這根本不是一元的,因此您需要使用fmap<$>來解除它。 考慮運算符優先級。

     fmap homeDirectory $ getUserEntryForID =<< getRealUserID homeDirectory <$> (getUserEntryForID =<< getRealUserID)

因為 monad 是關聯的,所以你也可以反過來做:

  1. 使用getUserEntryForID編寫homeDirectory 后者已經是標准的Kleisli 箭頭,您也可以將homeDirectory提升到 Kleisli 以使用 Kleisli 組合運算符:

     pure. homeDirectory:: UserEntry -> IO String pure. homeDirectory <=< getUserEntryForID:: UserId -> IO String
  2. 再次將整個內容應用於getRealUserID

     (pure. homeDirectory <=< getUserEntryForID) =<< getRealUserID

事實上,您也可以使用 dummy ()參數將getRealUserID轉換為 Kleisli 箭頭。 這種風格在 Haskell 中相當少見,但它的優點是 Kleisli 組合的關聯性變得明顯,就像正常的 function 組合一樣明顯:

pure . homeDirectory <=< getUserEntryForID <=< const getRealUserID $ ()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM