【问题标题】:How can fmap be used with a data constructor?fmap 如何与数据构造函数一起使用?
【发布时间】:2018-02-25 07:25:32
【问题描述】:

我正在尝试理解一些 haskell 代码。

这是有道理的。

Prelude> fmap (+1) (Just 1)
Just 2

这也是有道理的。

Prelude> (fmap.fmap) (+1) (Just [1])
Just [2]

但我不明白这是如何工作的。

Prelude> (fmap.fmap) (+1) Just 1
Just 2

我已经尝试解决这些部件。在我看来,这就是正在发生的事情。

(fmap (fmap (+1)) Just) 1

我尝试输入子表达式。

这是有道理的。

Prelude> :t fmap (+1)
fmap (+1) :: (Functor f, Num b) => f b -> f b

这还是有道理的。

Prelude> :t fmap (fmap (+1))
fmap (fmap (+1)) :: (Functor f, Functor f1, Num b) =>
    f (f1 b) -> f (f1 b)

但我不明白这一点。

Prelude> :t fmap (fmap (+1)) Just
fmap (fmap (+1)) Just :: Num b => b -> Maybe b

一个函数的类型如何

(Functor f, Functor f1, Num b) => f (f1 b) -> f (f1 b)

在应用 Just 后,其类型为:

a -> Maybe a

导致这种类型?

Num b => b -> Maybe b

confused about function as instance of Functor in haskell的问题可能和这个有关,但我还是很困惑。

【问题讨论】:

    标签: haskell functor


    【解决方案1】:

    发生的事情是 f 解析为仿函数 (->) a,而 f1 解析为 Maybe,因为

    Just :: (->) a (Maybe a)
    

    所以如果我们用上面的绑定写fmap (fmap (+1))的类型,我们得到:

    fmap (fmap (+1)) :: Num b => (->) a (Maybe b) -> (->) a (Maybe b)
    

    (->)重写为我们得到的中缀构造函数:

    fmap (fmap (+1)) :: Num b => (a -> Maybe b) -> (a -> Maybe b)
    

    现在我们将它应用到Just :: a -> Maybe a 所以我们得到

    fmap (fmap (+1)) Just :: Num a => a -> Maybe a
    

    【讨论】:

      【解决方案2】:

      您写的是Just 1 而不是(Just 1),因此,这是两个单独的参数。我们现在可以用更规范的形式重写它,比如:

         (fmap . fmap) (+1) Just 1
      -> (\x -> fmap (fmap x)) (+1) Just 1
      -> ((fmap (fmap (+1)) Just) 1
      

      所以现在我们可以分析类型了:

      fmap1 :: Functor f => (a -> b) -> f a -> f b
      fmap2 :: Functor g => (c -> d) -> g c -> g d
      (+1) :: Num h => h -> h
      Just :: i -> Maybe i
      1 :: Num j => j

      fmap<i>i</i> 是表达式中的第 ifmap(如果我们从左到右阅读)。如果我们知道执行一些分析,我们会看到由于我们使用fmap (+1),我们知道c ~ d ~ h

      fmap1 :: Functor f => (a -> b) -> f a -> f b
      fmap2 :: Functor g => (h -> h) -> g h -> g h
      (+1) :: Num h => h -> h
      Just :: i -> Maybe i
      1 :: Num j => j

      然后我们看到第一个 fmap (fmap<i>1</i>) 被调用,fmap (+1) :: Functor g =&gt; g h -&gt; g h 作为第一个参数,Just :: i -&gt; Maybe i 作为第二个参数。所以如果我们进一步进行类型分析,我们得到:(a -&gt; b) ~ g h -&gt; g h,所以a ~ b ~ g h,我们知道f (g h) ~ i -&gt; Maybe i,所以这意味着f (g h) ~ (-&gt;) i (Maybe i),所以f ~ (-&gt;) ig ~ Maybeh ~ i,还有@987654342 @:

      fmap1 :: (Maybe i -> Maybe i) -> (->) i (Maybe i) -> (->) i Maybe i
      fmap2 :: (i -> i) -> Maybe i -> Maybe i
      (+1) :: Num h => i -> i
      Just :: i -> Maybe i
      1 :: Num i => i

      现在这里的一个关键方面是(-&gt;) r 也是一个函子,实际上在我们看到的base-4.10.1.0 source code 中:

      instance Functor ((->) r) where
          fmap = (.)
      

      我们可以在这里将函数视为函子,如果我们执行fmap,我们会“后处理”结果。所以这意味着我们应用Just 之后,我们将fmap (+1) 应用到那个结果。所以第一个fmap 等价于(.) 而第二个是fmap 而不是Maybe,因此我们得到:

         ((fmap (fmap (+1)) Just) 1
      -> (((.) (fmap (+1)) Just) 1
      -> ((\x -> (fmap (+1) (Just x)) 1
      -> fmap (+1) (Just 1)
      -> Just 2
      

      所以简而言之,我们将(fmap (+1)) 用作后处理 步骤,之后我们将Just 应用于1

      【讨论】:

      • 最后一个代码 sn-p 中的部分,您在其中拼出第一个 fmap 是 (.),这对我来说非常清楚。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-01
      • 1970-01-01
      • 2020-10-05
      相关资源
      最近更新 更多