非平凡函子的示例

时间:2019-06-03 06:40:10

标签: haskell functor category-theory

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

那可折叠,可遍历,Semigroup等如何呢?有没有重要的案例?

5 个答案:

答案 0 :(得分:12)

我偶然发现了一种有趣的论点。 (很晚了,所以我想知道明天是否会有意义)

我们可以将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

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

(有一种替代的表达方式,我觉得它很优雅,但可能不那么具示范性:如果删除Red t构造函数,则Functort,当且仅当类型系统可以表示infoPopup.showAtLocation(view, Gravity.TOP, 0, (int) view.getY()); 的减少量发散 -有时它发散,但您无法证明这一点,我在这种情况下是否确实是函子感到困惑

答案 1 :(得分:9)

在这个问题上,没有非平凡的函子。所有函子都可以作为EitherTuple函子的和(Identity)和乘积(Const)进行机械推导。有关此构造的详细信息,请参见关于Functorial Algebraic Data Types的部分。

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

答案 2 :(得分:9)

可以将空的参数类型明确地自动创建为函子:

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)

可以说是一个法律实例。

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

答案 3 :(得分:4)

有点作弊,但是我们开始吧。根据{{​​3}},例如,当类型受到约束时,函子不能自动导出。

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!

答案 4 :(得分:1)

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有两个不同的实例这一事实向我表明,不能自动应用一组规则来覆盖所有可能的情况。