【问题标题】:Example of non-trivial functors非平凡函子的例子
【发布时间】:2019-06-03 06:40:10
【问题描述】:

在 Haskell 中,函子几乎总是可以派生的,是否存在类型是函子并且满足函子定律(例如 fmap id == id)但不能根据一组简单的规则派生的情况?

那么 Foldable、Traversable、Semigroup 等呢?有没有不平凡的案例?

【问题讨论】:

  • 当您不知道应该将函数应用于第一个值还是第二个值时,您的意思是元组之类的东西?
  • @talex 不,如果将 (a, b) 的元组视为 b 上的函子,则 fmap 的结果是 (a, c),从中可以很清楚哪个值应该函数 b -> c 被应用到。
  • Haskell 中的函子总是可以派生的。 Bartosz Milewski 在他的书*程序员的类别理论*[1] 中谈到了这一点。我需要自己查找确切的参考和详细信息,但这与 Haskell 中的函子形成某种代数有关。 [1]bartoszmilewski.com/2014/10/28/…
  • 可折叠、可遍历和半群都具有对称性,这允许它们以多种不同的方式合法地实例化,这至少是一种不平凡的感觉
  • @luqui,如果您使用 Atkey 样式的索引应用程序来定义类型对齐集合的可遍历概念,那么您应该恢复唯一性。

标签: haskell functor category-theory


【解决方案1】:

这是我偶然发现的一个有趣的论点。 (时间不早了,不知道明天会不会有感觉)

我们可以将SK可约化的证明类型构造为GADT:

infixl 9 :%:
data Term = S | K | Term :%: Term

-- small step, you can get from t to t' in one step
data Red1 t t' where
    Red1S :: Red1 (S :%: x :%: y :%: z) (x :%: z :%: (y :%: z))
    ...

现在让我们创建一个在归约链末端隐藏其函数的类型。

data Red t a where
    RedStep :: Red1 t t' -> Red t' a -> Red t a
    RedK    :: a                     -> Red K a
    RedS    :: (a -> Bool)           -> Red S a

如果t 规范化为K,则现在Red tFunctor,但如果规范化为S 则不是——这是一个无法确定的问题。因此,也许您仍然可以遵循“简单的规则集”,但如果您允许 GADT,则这些规则必须足够强大,可以计算任何东西。

(有一个替代公式,我觉得它相当优雅,但可能不太具有说服力:如果你放弃RedK 构造函数,那么Red tFunctor 当且仅当类型系统可以表达减少t diverges -- 有时它会发散,但你无法证明这一点,我想知道在这种情况下它是否真的是一个函子)

【讨论】:

  • 如果归约发散,为什么它不是函子?如果您在Red1 中选择确定性缩减策略,请定义data Blue t where BlueStep :: Red1 t t' -> Blue t' -> Blue t。 (对于非确定性策略,事情变得有点难看,因为您必须分离出所有重叠的规则)。现在您可以使用Red t aBlue t。在每一步,Blue t 中的Red1 t t' 证明t 不是S
  • @dfeuer,嗯,我不确定我是否在关注。当然我们可以得到t 在每一步都不是S,但为了证明函子性,我们需要在每一步
  • 我还没有完全到达那里,但是this gist 建立了我所勾画的框架,并在很大程度上表达了特定示例的分歧证明.
【解决方案2】:

可以自动将显式空参数类型制成函子:

data T a deriving Functor

但是,隐式空的不能:

import Data.Void
data T a = K a (a -> Void)
    deriving Functor  -- fails
{-
error:
    • Can't make a derived instance of ‘Functor T’:
        Constructor ‘K’ must not use the type variable in a function argument
    • In the data declaration for ‘T’
-}

然而,

instance Functor T where
   fmap f (K x y) = absurd (y x)

可以说是一个法律实例。

有人可能会争辩说,利用底部,可以为上面的例子找到函子定律的反例。然而,在这种情况下,我想知道是否所有“标准”仿函数实例实际上都是合法的,即使存在底部也是如此。 (也许是?)

【讨论】:

  • 我相信大多数常见的Functor 实例即使有底部也是有效的。这是一个简单的类型 GHC 无法为:data Foo a = Foo (a -> Bool) !Void 派生 Functor。还有另一种方式可以阻碍逆变:newtype Bar f a = Bar (f a -> Bool)。 GHC 无法导出完全有效的实例instance Contravariant f => Functor (Bar f) where fmap f (Bar g) = Bar (g . contramap f)。主要问题是,将Contravariant 添加到派生组合中会导致newtype Baz f g a = Baz (f (g a)) 之类的多个潜在实例(具有不兼容的约束)。
【解决方案3】:

在问题的意义上没有非平凡的函子。所有函子都可以机械地导出为 IdentityConst 函子的和 (Either) 和乘积 (Tuple)。请参阅有关Functorial Algebraic Data Types 的部分以了解此构造的详细工作原理。

在更高的抽象层次上这是可行的,因为 Haskell 的类型形成了 Cartesian Closed Category,其中存在终端对象、所有乘积和所有指数。

【讨论】:

    【解决方案4】:

    这有点作弊,但我们开始吧。根据this,当类型受到限制时,仿函数不能自动派生,例如。

    data A a where
        A1 :: (Ord a) => a -> A a
    deriving instance Functor A -- doesn't work
    

    事实上,如果(比如说)我们编写了一个手动版本,它也不会起作用。

    instance Functor A where
        fmap f (A1 a) = A1 (f a) -- Can't deduce Ord for f a
    

    但是,由于算法所做的所有工作都是检查不存在约束,因此我们可以引入一个类型类,每个类型都是其成员。

    class C c
    instance C c
    

    现在用C 代替Ord 进行上述操作,

    data B b where
        B1 :: (C b) => b -> B b
    
    deriving instance Functor B -- doesn't work
    
    instance Functor B where
        fmap f (B1 b) = B1 (f b) -- does work!
    

    【讨论】:

      【解决方案5】:

      base 中有一个标准类型,称为Compose,定义如下:

      newtype Compose f g a = Compose { getCompose :: f (g a) }
      

      派生的Functor实例是这样实现的:

      instance (Functor f, Functor g) => Functor (Compose f g) where
          fmap f (Compose v) = Compose (fmap (fmap f) v)
      

      但还有另一个完全合法的例子,但行为不同:

      instance (Contravariant f, Contravariant g) => Functor (Compose f g) where
          fmap f (Compose v) = Compose (contramap (contramap f) v)
      

      对我来说,Compose 可以使用两个不同的实例这一事实表明,没有任何规则可以自动应用于涵盖所有可能的情况。

      【讨论】:

      • 在两组约束都成立的情况下(即,当fg 都具有幻像参数时),实例具有相同的行为。所以我想说这是关于不兼容的约束,而不是不同的行为。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-05
      • 1970-01-01
      • 1970-01-01
      • 2011-01-18
      • 2015-12-11
      • 2021-02-13
      相关资源
      最近更新 更多