我正在尝试编写一些IO封装的函数。
我目前的代码(有效(是:
getUserHome :: IO String
getUserHome = do
usr_id <- getRealUserID
homeDirectory <$> getUserEntryForID usr_id
我正在寻找一种更方便的表示法(不使用do
-关键字(。
如果没有任何Monadic沙拉,我只会写
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最终"desugars";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
现在您可以:
应用
getRealUserID
和getUserEntryForID
。这直接适合(>>=) :: m a -> (a -> m b ) -> m b (>>=) :: IO UserId -> (UserId -> IO UserEntry) -> IO UserEntry
事实上,如果你想让它看起来像一个合成链,我更喜欢翻转版本,即
getUserEntryForID =<< getRealUserID :: IO UserEntry
对此应用
homeDirectory
。在你的情况下,这根本不是一元的,所以你需要用fmap
或<$>
来提升它。考虑运算符优先级。fmap homeDirectory $ getUserEntryForID =<< getRealUserID homeDirectory <$> (getUserEntryForID =<< getRealUserID)
因为单子是关联的,你也可以用另一种方法:
用
getUserEntryForID
组成homeDirectory
。后者已经是一个标准的Kleisli箭头,您也可以将homeDirectory
提升到Kleisli,以便使用Kleisli合成运算符:pure . homeDirectory :: UserEntry -> IO String pure . homeDirectory <=< getUserEntryForID :: UserId -> IO String
再次将整件事应用于
getRealUserID
:(pure . homeDirectory <=< getUserEntryForID) =<< getRealUserID
事实上,您也可以使用伪()
参数将getRealUserID
转换为Kleisli箭头。这种风格在Haskell中并不常见,但它的优点是Kleisli组合的结合性变得明显,就像正常函数组合一样:
pure . homeDirectory <=< getUserEntryForID <=< const getRealUserID $ ()