所以我发现fmap
,Functor
函数可以用Monadic运算符>>=
和return
函数来表示:
fmap' :: (Monad m) => (a -> b) -> m a -> m b
fmap' g x = x >>= (\y ->
return (g y))
所以我的第一个问题是如何基于fmap
实现返回功能?
另外如果我们可以基于fmap
实现返回函数,我们可以减少do块中的Haskell表达式吗?这会产生更优雅的代码吗?
例如:
Just x -> do
y <- f x
return (a:y)
答案 0 :(得分:3)
我们通常无法在return
方面实施fmap
。 Monad
比Functor
更强大。
但是,作为一项练习,我们可以尝试提出这样一个问题:第二项操作(如果有的话)是否可以在return
轮流中实施fmap
?我们可以通过查看类型来攻击这个问题。 (我们将使用pure
类中的Applicative
而不是return
- 它们基本上是相同的操作。)
fmap :: Functor f => (a -> b) -> f a -> f b
pure :: Applicative f => a -> f a
嗯,这可能是一种可能的方法,如果我们有以下功能:
-- This is like the standard `const` function, but restricted to the `()` type:
const' :: a -> () -> a
const' a = \() -> a
然后我们可以写这个,“几乎是”pure
/ return
:
almostThere :: Functor f => a -> f () -> f a
almostThere a = fmap (const' a)
然后,如果我们有以下课程,我们可以用它来写pure
:
class Functor f => Pointed f where
unit :: f ()
pure :: Pointed f => a -> f a
pure a = almostThere a unit
简而言之,这归结为return
,pure
和unit
都是允许您从头开始制作f
的功能,fmap
只允许您制作f
,如果您已经另一个。您无法使用fmap
来实施return
/ pure
,除非您可以访问具有从头开始制作f
的“权力”的第三个操作。我展示的unit
操作可能是最简单的具有“权力”的操作。
答案 1 :(得分:2)
只有return
不可能的仿函数最简单的例子是(,) a
:
instance Functor ((,) a) where
fmap f (a, x) = (a, f x)
但要使其成为monad,要实现return
,您需要凭空生成a
值(适用于任何类型!)。唯一的方法是return x = (undefined, x)
,这几乎不是解决方案......