简体   繁体   English

以下类型的 Functor 实例是什么: newtype F2 xa = F2 ((a -> x) -> a)

[英]What would be the Functor instance for the following type: newtype F2 x a = F2 ((a -> x) -> a)

So I want to write the fmap function for the above mentioned type, but I am stuck here:所以我想为上述类型编写fmap function,但我被困在这里:

instance Functor (F2 x) where
 fmap :: (a -> b) -> (F2 x a) -> (F2 x b)
 fmap f (F2 g) = F2 ( f _ )

A good strategy here is to follow the types.这里一个好的策略是遵循类型。 GHC can help us along the way if we write incomplete definitions with typed holes :如果我们用类型空洞编写不完整的定义,GHC 可以帮助我们:

newtype F2 x a = F2 ((a -> x) -> a)

instance Functor (F2 x) where
    fmap f (F2 g) = _

If we try to compile this, GHC reports back:如果我们尝试编译它,GHC 会报告:

Diatonic.hs:275:21: error:
    • Found hole: _ :: F2 x b
      Where: ‘b’ is a rigid type variable bound by
               the type signature for:
                 fmap :: forall a b. (a -> b) -> F2 x a -> F2 x b
               at Diatonic.hs:275:5-8
             ‘x’ is a rigid type variable bound by
               the instance declaration
               at Diatonic.hs:274:10-23
    • In the expression: _
      In an equation for ‘fmap’: fmap f (F2 g) = _
      In the instance declaration for ‘Functor (F2 x)’
    • Relevant bindings include
        g :: (a -> x) -> a (bound at Diatonic.hs:275:16)
        f :: a -> b (bound at Diatonic.hs:275:10)
        fmap :: (a -> b) -> F2 x a -> F2 x b (bound at Diatonic.hs:275:5)
    |
275 |     fmap f (F2 g) = _
    |                 

This means we have to fill the hole with an F2 xb value.这意味着我们必须用F2 xb值填充孔。 The only way we have of creating one is by using the constructor (for the following steps, I will omit the unchanging boilerplate):我们创建一个的唯一方法是使用构造函数(对于以下步骤,我将省略不变的样板):

fmap f (F2 g) = F2 _
• Found hole: _ :: (b -> x) -> b

So we need a function that takes a b -> x .所以我们需要一个带有b -> x的 function 。 We can set up one.我们可以设置一个。 Let's call its argument k , and see if we can complete its body:让我们调用它的参数k ,看看我们是否可以完成它的主体:

fmap f (F2 g) = F2 (\k -> _)
• Found hole: _ :: b

The only thing that can produce a b is f:: a -> b :唯一可以产生 a b的是f:: a -> b

fmap f (F2 g) = F2 (\k -> f _)
• Found hole: _ :: a

The only thing that can produce an a is g:: (a -> x) -> a :唯一可以产生ag:: (a -> x) -> a

fmap f (F2 g) = F2 (\k -> f (g _))
• Found hole: _ :: a -> x

We are supposed to provide an a -> x function, so let's throw in another lambda (for a possible shortcut, see the final part of the answer):我们应该提供一个a -> x function,所以让我们加入另一个 lambda(可能的捷径,请参阅答案的最后部分):

fmap f (F2 g) = F2 (\k -> f (g (\a -> _)))
• Found hole: _ :: x

The only thing that can produce a x is k:: b -> x唯一能产生x的是k:: b -> x

fmap f (F2 g) = F2 (\k -> f (g (\a -> k _)))
• Found hole: _ :: b

The only thing that can produce a b still is f:: a -> b :唯一可以产生 a b仍然是f:: a -> b

fmap f (F2 g) = F2 (\k -> f (g (\a -> k (f _))))
• Found hole: _ :: a

If we try to use g to create an a value like we did several steps ago, we will get trapped in a vicious circle.如果我们像前几步那样尝试使用g创建a值,我们将陷入恶性循环。 However, we don't have to do that this time, as the a argument of the lambda is in scope:但是,这次我们不必这样做,因为 lambda a参数在 scope 中:

fmap f (F2 g) = F2 (\k -> f (g (\a -> k (f a))))

And we are done.我们完成了。

(It is worth mentioning that your F2 is provided by transformers , where it is known as Select .) (值得一提的是,您的F2是由transformers提供的, 它被称为Select 。)

The definition arguably looks a little tidier if we write \a -> k (fa) pointfree:如果我们写成\a -> k (fa) pointfree,这个定义可以说看起来更整洁一些:

instance Functor (F2 x) where
    fmap f (F2 g) = F2 (\k -> f (g (k . f)))

We might have skipped directly from the a -> x hole to here by noticing our only viable option there was composing f:: a -> b and k:: b -> x .通过注意到我们唯一可行的选择是组合f:: a -> bk:: b -> x ,我们可能已经直接从a -> x洞跳到了这里。

You can make GHC do the hard work for you:您可以让 GHC 为您完成艰苦的工作:

GHCi, version 8.8.2: https://www.haskell.org/ghc/  :? for help
Prelude> :set -ddump-deriv -dsuppress-all -XDeriveFunctor
Prelude> newtype F2 x a = F2 ((a -> x) -> a) deriving(Functor)

==================== Derived instances ====================
Derived class instances:
  instance Functor (F2 x) where
    fmap f_a1bk (F2 a1_a1bl)
      = F2
          ((\ b4_a1bm b5_a1bn
              -> f_a1bk
                   (b4_a1bm
                      ((\ b2_a1bo b3_a1bp
                          -> (\ b1_a1bq -> b1_a1bq) (b2_a1bo (f_a1bk b3_a1bp)))
                         b5_a1bn)))
             a1_a1bl)
    (<$) z_a1br (F2 a1_a1bs)
      = F2
          ((\ b6_a1bt b7_a1bu
              -> (\ b5_a1bv -> z_a1br)
                   (b6_a1bt
                      ((\ b3_a1bw b4_a1bx
                          -> (\ b2_a1by -> b2_a1by)
                               (b3_a1bw ((\ b1_a1bz -> z_a1br) b4_a1bx)))
                         b7_a1bu)))
             a1_a1bs)


Derived type family instances:


Prelude>

Rename GHC's weird names and remove its excessive indentation, and you end up with this:重命名 GHC 的奇怪名称并删除其过多的缩进,你最终会得到这样的结果:

instance Functor (F2 x) where
  fmap f (F2 a1) = F2 ((\b4 b5 -> f (b4 ((\b2 b3 -> (\b1 -> b1) (b2 (f b3))) b5))) a1)

Now we can do some simplification to make that more understandable.现在我们可以做一些简化以使其更容易理解。 Let's look at this subexpression:让我们看看这个子表达式:

(\b2 b3 -> (\b1 -> b1) (b2 (f b3))) b5

(\b1 -> b1) is the identity function, which we can beta-reduce to get rid of: (\b1 -> b1)是标识 function,我们可以通过 beta-reduce 来消除它:

(\b2 b3 -> b2 (f b3)) b5

Now we can beta-reduce again, this time b5 for b2 :现在我们可以再次进行 beta-reduce,这次是b5b2

\b3 -> b5 (f b3)

This is now clearly equivalent to b5. f这现在显然等同于b5. f b5. f . b5. f . Plug it back in:重新插入:

instance Functor (F2 x) where
  fmap f (F2 a1) = F2 ((\b4 b5 -> f (b4 (b5 . f))) a1)

One more beta-reduction: a1 for b4 :另一个 beta 减少: a1b4

instance Functor (F2 x) where
  fmap f (F2 a1) = F2 (\b5 -> f (a1 (b5 . f)))

And we're done.我们完成了。 No hard work on our part needed.我们不需要付出任何努力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM