给出函数 fmap :: (a->b) -> IO a -> IO b 的定义
其效果是通过将函数应用于其结果来转换交互。您应该使用 do 构造来定义它。
我应该如何定义 fmap?我对此一无所知?
有人可以帮我吗?
谢谢~!
它看起来像家庭作业或其他东西,所以我会给你足够的提示,这样你就可以自己处理其余的细节。
fmap1 :: (a -> b) -> IO a -> IO b
fmap1 f action =
action
is 作为IO
动作,f
是来自a
to的函数b
,因此是 type a -> b
。
如果您熟悉>>=
具有类型的 monadic bind(简化为IO
monad)
(>>=) :: IO a -> (a -> IO b) -> IO b
现在如果你看
action >>= f
这意味着执行IO
返回输出(例如out
type a
)并将输出传递给f
type 的操作a -> IO b
,因此f out
是 type IO b
。
如果您查看第二个调用return
的具有类型的函数(再次简化为IO
monad)
return :: a -> IO a
它接受 type 的纯值a
并给出 type 的IO
动作IO a
。
现在让我们回顾一下fmap
。
fmap1 f action
它执行IO
动作,然后f
在动作的输出上运行,然后将输出转换为另一个IO
类型的动作IO b
。所以
fmap1 f action = action >>= g
where
g out = return (f out)
现在是do
符号的语法糖。这只是以另一种方式编写绑定>>=
。
在do
符号中,您可以通过以下方式获得操作的输出
out <- action
所以 bind 只是减少到
action >>= f = do
out <- action
f out
我认为现在您将能够将 fmap 的定义转换为 do 构造。
你熟悉地图吗?
地图的类型是
地图 :: (a -> b) -> [a] -> [b]
如果你跑
地图 (*5) [1,2,3]
你得到
[5,10,15]
map 的重点是给它一个转换函数和一个源列表,并让它将转换应用于列表以获得结果列表。
map 是列表的 fmap。他们希望您为 IO 类型编写 fmap,这有帮助吗?
如果您想了解更多关于 fmap 的信息,请阅读http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclass
请注意,每个 monad 已经是一个仿函数。但是,如果你想重新实现fmap
,你可以很容易地用一元函数来做到这一点。一个单子定律是这样的:
fmap f xs = xs >>= return . f
如果你对 do notation 的理解足够,你应该可以自己翻译。如果没有,请问。