【问题标题】:In the declaration of class Functor, can the type variables be function types?在类 Functor 的声明中,类型变量可以是函数类型吗?
【发布时间】:2019-07-17 23:02:29
【问题描述】:

在 Haskell 中,Functor 类声明为:

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

类型变量ab 可以是函数类型,还是必须是非函数类型?

如果它们可以是函数类型,那么在使fmap 能够应用于具有任意数量参数的函数方面,Functor 类是否与Applicative 类实际上相同?根据 Hutton 的 Haskell 编程 所说:

仿函数抽象了fmap 将函数映射到结构的每个元素的想法。应用程序将这个想法概括为允许 fmap 映射具有任意数量参数的函数,而不是仅限于具有单个参数的函数。

在应用中:

fmap0 ::  a   ->  f   a
fmap0 =   pure
fmap1 ::  (a  ->  b)  ->  f   a   ->  f   b
fmap1 g   x   =   pure    g   <*> x
fmap2 ::  (a  ->  b   ->  c)  ->  f   a   ->  f   b   ->  f   c
fmap2 g   x   y   =   pure    g   <*> x   <*> y
fmap3 ::  (a  ->  b   ->  c   ->  d)  ->  f   a   ->  f   b   ->  f   c   ->  f   d
fmap3 g   x   y   z   =   pure    g   <*> x   <*> y   <*> z

Applicative 类声明为:

class Functor f   =>  Applicative f   where
pure  ::  a   ->  f   a
(<*>) ::  f   (a  ->  b)  ->  f   a   ->  f   b

谢谢。

【问题讨论】:

  • ab 可以是函数类型。
  • 那么应用程序能做什么而函子不能呢?查看我的更新
  • 您对fmap1 的实现使用Applicative 方法。这表明仅仅拥有Applicative 就足以实现Functor。但是您的问题是另一种方式:仅拥有Functor 就足以实现Applicative 吗?我认为,如果您尝试另辟蹊径——尝试写下pure(&lt;*&gt;) 的实现,只在右侧使用fmap(以及纯粹的东西)——你会发现自己很快就卡住了确实。
  • b 可以是一个函数类型这一事实就是为什么Applicative 存在:fmap (+) (Just 3) == Just (+3)Applicative 允许您将部分应用 + 的结果应用于另一个 Just 值。 fmap (+) (Just 3) &lt;*&gt; Just 5 == Just (+3) &lt;*&gt; Just 5 == Just 8.

标签: haskell types functor applicative


【解决方案1】:

变量ab可以是函数类型

– 是的,当然。

难道不是Functor 类实际上与Applicative 类相同

不,绝对不是。如果你在fmap 签名的ab 中插入一个函数类型,你会得到类似

fmap :: ((x -> y) -> b) -> f (x -> y) -> f b

fmap :: (a -> p -> q) -> f a -> f (p -> q)

但至关重要的是,fmap 总是只取一个 f _ 包装值并准确地吐出一个这样的值。 Applicative 同时允许你接受任意数量的包装值,只要你给它一个函数来处理包含的值。

【讨论】:

  • 谢谢。在我的帖子中,fmap0fmap1 在类型的类别上形成内函子是否正确? fmap0, fmap1, fmap2, ... 是什么形式?
  • 没有。函子由对象(即类型)和态射之一(即函数)的映射形成。 fmap1 确实是函数的映射,但fmap0 的映射,而不是类型的映射。在Functor 类中,对象的映射是隐式的:它是类型构造函数f 本身。
【解决方案2】:

ab 可以是函数类型。它们可以是任何类型。事实上,一个有效的Functor必须允许它们是任何类型。

要回答您的Applicative 问题,让我们试试吧。

fmap :: (a -> b -> c) -> f a -> f (b -> c)

好的,太好了!现在我可以将f a 转换为f (b -&gt; c)。但是……然后呢?我不能将f (b -&gt; c) 应用于参数。这不是一个函数;这是我的仿函数类型的值。要是我们有一个带有这个签名的函数就好了……

superFmap :: f (b -> c) -> f b -> f c

但这确实看起来很像

(<*>) :: f (b -> c) -> f b -> f c

它是Applicative 的成员。因此,我们需要Applicative 才能应用此次要结果。

其他答案所说的是正确的。出于类似的原因,我们也无法实现pure。但重要的是要注意,我们甚至无法获得一般的(&lt;*&gt;),因为如果我们可以,那将意味着每个Functor 都是Apply,当然也不是这样。

【讨论】:

    【解决方案3】:

    类型变量ab 可以是函数类型,还是必须是非函数类型?

    ab 可以是 any 类型,函数类型也是如此。

    例如我们可以使用:

    fmap <b>(+)</b> [1,4,2,5]

    这里(+) 有类型:

    fmap :: Functor f => (a -> b       ) -> f a -> f b
    (+)  :: Num c =>      c -> (c -> c)
    

    所以这里b ~ c -&gt; cb 因此是一个函数。

    a 是一个函数的例子是:

    fmap <b>($ 2)</b> [ (1+), (2*), (3-) ]

    这里我们有类型:

    fmap :: Functor f => (a        -> b) -> f a -> f b
    ($ 3)  :: Num c =>    (c -> d) -> d
    

    所以a ~ (c -&gt; d) 在这里,我们因此将3 应用于列表中的所有函数。

    请注意,我们没有在此处添加额外的 fmap 定义(如 fmap<sub>1</sub>fmap<sub>2</sub>、...)。只是a 可以替换为c -&gt; d 等类型)。

    如果它们可以是函数类型,那不是Functor 类实际上与Applicative 类相同吗?

    不,因为例如没有说可以为给定的Functor 实现pure。例如,想象一下您创建了一个数据类型:

    type Owner = String
    
    data Owned a = Owned Owner a

    那么Owned可以实现为Functor的一个实例:

    instance Functor Owned where
        fmap f (Owned o x) = Owned o (f x)

    但是实现pure :: a -&gt; Owned a 是不可能的:为什么会是对象的所有者?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-06
      • 2021-07-28
      • 2010-09-28
      • 2018-05-02
      相关资源
      最近更新 更多