【问题标题】:Haskell function composition and fmap fHaskell 函数组合和 fmap f
【发布时间】:2018-01-11 16:40:43
【问题描述】:

我有两个简单的例子:

1) xt 函数(这是什么?)

Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> :{
Prelude| f::Int->Int
Prelude| f x = x
Prelude| :}
Prelude> xt = fmap f // ?
Prelude> :t xt
xt :: Functor f => f Int -> f Int
Prelude> xt (+2) 1
3

2) xq 函数(通过合成)

Prelude> :{
Prelude| return x = [x]
Prelude| :}
Prelude> xq = return . f
Prelude> :t xq
xq :: Int -> [Int]
Prelude> :t return
return :: a -> [a]

xq 函数我通过组合 return(f(x)) 获得。但这是什么意思:fmap f 和有什么区别?

【问题讨论】:

  • @chepner 我的问题不是,functor 是什么。我想知道fmap f这个符号是什么意思
  • 如果你知道函子是什么,那么fmap f 的含义就很明显了。不是特殊语法,只是函数应用。

标签: haskell


【解决方案1】:

(->) rFunctor 实例将 fmap 定义为函数组合:

fmap f g = f . g

因此,xt (+2) == fmap f (+2) == f . (+2) == (+2)(因为fInt 的标识函数)。应用到 1,你得到观察到的答案 3。


fmapFunctor类型类定义的函数:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

它将一个函数作为参数,并返回一个“提升”到相关仿函数中的新函数。确切的定义由Functor 实例提供。以上是函数函子的定义;这里供参考的是一些更简单的列表和Maybe

instance Functor [] where
    fmap = map

instance Functor Maybe where
    fmap f Nothing = Nothing
    fmap f (Just x) = Just (f x)

> fmap (+1) [1,2,3]
[2,3,4]
> fmap (+1) Nothing
Nothing
> fmap (+1) (Just 3)
Just 4

由于您可以将函子视为包含一个或多个值的盒子,因此函数函子的直觉是函数是一个包含将函数应用于其参数的结果的盒子。也就是说,(+2) 是一个包含某个值加 2 的框。 (F) 在该框上映射一个函数提供了一个框,该框包含将f 应用于原始函数的结果的结果,即产生一个函数也就是f与原函数的组合。

【讨论】:

  • 谢谢,但是下面的语法是什么意思fmap f?这不是两个功能的产物。是吗?
  • fmap ffmap 应用于f,从而产生一个函数。就像negate 3negate 应用于3,结果是一个数字
  • "fmap 将一个函数作为其参数,并将一个新函数“提升”到所讨论的函子中”。 xt = fmap f 所以xt :: Functor f => f Int -> f Int,但是为什么我不能写fmap . f,这里有什么问题? return . f 作文有效,我没有收到任何错误。 fmap. fmap也...
  • fmap 接受一个函数作为参数;它不适用于函数的返回值。考虑map(对于列表来说是fmap):map (+1) [1,2,3] 不适用于列表(+1),然后将结果传递给map;相反,map 将 (+1)` 作为参数并返回一个 new 函数,该函数将列表作为其输入。
  • @garychaudhry \f -> fmap . f :: Functor f => (c -> a -> b) -> c -> f a -> f b,所以为了使fmap . f 有意义,f 应该具有f :: c -> a -> b 类型。例如,fmap . (*) 有效 - 因为(fmap . (*)) 3 = fmap ((*) 3) = fmap (3*)。我们可以在 GHCi 提示符下使用:t 命令找到表达式的类型,例如Prelude> :t fmap . (*)
【解决方案2】:

xq = return . fxt = fmap f 都可以进行 eta 扩展

xq x = (return . f) x = return (f x) = return x

现在可以eta-contracted

xq = return

第二个是

xt y = fmap f y = fmap (\x -> x) y = fmap id y = id y = y

fmap 的类型为:: Functor f => (a -> b) -> f a -> f b,所以fmap f 的类型为:: Functor f => f Int -> f Int,因为f :: Int -> Int。从它的类型我们可以看出fmap f 是一个函数,期望一个Int,并产生一个Int

由于f x = x 定义为Ints,这意味着f = id 用于Ints,其中id 是一个预定义函数,其定义方式与f 相同(但通常,适用于任何类型)。

然后根据函子定律 (这就是我们需要了解的“函子”所有fmap id = idxt y = y,换句话说,它也是 id - 但仅限于 Ints,

xt = id :: Int -> Int

当然,xt (+2) = id (+2) = (+2)


附录:作为“函子”的东西意味着它可以替代f in

fmap id (x :: f a) = x
(fmap g . fmap h)  = fmap (g . h)

这样所涉及的表达式才有意义(即格式正确,即具有类型),并且上述方程成立(它们实际上是两个“函子定律”)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    相关资源
    最近更新 更多