所有固定大小的容器是否都具有很强的单曲面函子,反之亦然?


9

Applicative类型类代表松懈monoidal函子是保留对输入功能类别的笛卡尔monoidal结构。

换句话说,给定的规范同构见证(,)形成一个单面结构:

-- Implementations left to the motivated reader
assoc_fwd :: ((a, b), c) -> (a, (b, c))
assoc_bwd :: (a, (b, c)) -> ((a, b), c)

lunit_fwd :: ((), a) -> a
lunit_bwd :: a -> ((), a)

runit_fwd :: (a, ()) -> a
runit_bwd :: a -> (a, ())

类型类及其定律可以等效地编写为:

class Functor f => Applicative f
  where
  zip :: (f a, f b) -> f (a, b)
  husk :: () -> f ()

-- Laws:

-- assoc_fwd >>> bimap id zip >>> zip
-- =
-- bimap zip id >>> zip >>> fmap assoc_fwd

-- lunit_fwd
-- =
-- bimap husk id >>> zip >>> fmap lunit_fwd

-- runit_fwd
-- =
-- bimap id husk >>> zip >>> fmap runit_fwd

有人可能想知道,对于同一结构,呈单极单调的函子可能是什么样的:

class Functor f => OpApplicative f
  where
  unzip :: f (a, b) -> (f a, f b)
  unhusk :: f () -> ()

-- Laws:

-- assoc_bwd <<< bimap id unzip <<< unzip
-- =
-- bimap unzip id <<< unzip <<< fmap assoc_bwd

-- lunit_bwd
-- =
-- bimap unhusk id <<< unzip <<< fmap lunit_bwd

-- runit_bwd
-- =
-- bimap id unhusk <<< unzip <<< fmap runit_bwd

如果我们考虑一下定义和法律所涉及的类型,就会发现令人失望的事实。OpApplicative没有比Functor以下更具体的约束:

instance Functor f => OpApplicative f
  where
  unzip fab = (fst <$> fab, snd <$> fab)
  unhusk = const ()

但是,尽管每个Applicative函子(实际上Functor是任何一个)都是微不足道的OpApplicative,但松驰度ApplicativeOpApplicative奥普拉斯度之间不一定存在良好的关系。因此,我们可以使用笛卡尔单曲面结构来寻找强单曲面仿函数:

class (Applicative f, OpApplicative f) => StrongApplicative f

-- Laws:
-- unhusk . husk = id
-- husk . unhusk = id
-- zip . unzip = id
-- unzip . zip = id

上面的第一定律是微不足道的,因为该类型的唯一居民() -> ()是上的恒等函数()

但是,其余的三个定律,以及子类本身,也不是小事。具体来说,并非每个Applicative都是此类的合法实例。

以下是一些Applicative函子,我们可以为它们声明合法的实例StrongApplicative

  • Identity
  • VoidF
  • (->) r
  • Monoid m => (,) m (查看答案)
  • Vec (n :: Nat)
  • Stream (无限的)

以下是一些Applicative我们无法做到的:

  • []
  • Either e
  • Maybe
  • NonEmptyList

这里的模式表明,StrongApplicative在某种意义上,阶级是FixedSize阶级,其中“固定大小” *表示的居民中的居民的多样性**是固定的。af a

这可以说是两个推测:

  • 每个Applicative代表其类型实参元素的“固定大小”容器的实例都是StrongApplicative
  • StrongApplicative存在发生次数a可以变化的实例

谁能想到反驳这些猜想的反例,或一些令人信服的论证,证明它们是真还是假?


*我意识到我没有正确定义形容词“固定大小”。不幸的是,这项任务有点循环。我不知道“固定大小”容器的任何正式描述,并且正在尝试提出一个。StrongApplicative是迄今为止我最好的尝试。

为了评估这是否是一个好的定义,我需要进行一些比较。给定某种形式的/非正式的定义,对于一个函子,对于其类型参数的居民而言,具有给定的大小或多重性意味着什么,问题是StrongApplicative实例的存在是否精确地区分了固定大小和变化大小的函子。

由于不了解现有的正式定义,因此我在使用“固定大小”一词时要求直觉。但是,如果有人已经知道函子大小的现有形式主义并且可以与之进行比较StrongApplicative,那就更好了。

**“多重性”在广义上是指函子的共域类型的居民中出现了多少个函子的参数类型的任意元素。这是没有考虑到函子被施加到特定类型的,因此不考虑参数类型的任何特定居民。

对此不够精确,导致评论有些混乱,因此以下是一些我认为各种函子的大小/多重性的示例:

  • VoidF固定0
  • Identity固定1
  • Maybe:变量,最小0,最大1
  • []:变量,最小0,最大无限
  • NonEmptyList:变量,最小1,最大无限
  • Stream:固定,无限
  • Monoid m => (,) m固定1
  • data Pair a = Pair a a固定2
  • Either x:变量,最小0,最大1
  • data Strange a = L a | R a固定1

评论不作进一步讨论;此对话已转移至聊天
塞缪尔·柳

“固定大小”的一种可能定义是“可代表”。就此处描述的意义而言,所有可表示的函子都是强应用,因为(->) ris是正确的。
丹尼尔·瓦格纳

@DanielWagner我想您不仅需要同构来继承强大的应用程序(->) r; 您需要同构的组件来保留强大的应用结构。出于某种原因Representable,Haskell中的类型类具有一个神秘的tabulate . return = return定律(对于非二元函子甚至没有意义),但它为我们提供了我们需要说的条件的1/4,tabulate并且zip是适合的类半定形词的态射。其他3条是您必须要求的额外法律。
Asad Saeeduddin

抱歉,应该是“ tabulate并且index是适当类别的
词素

@AsadSaeeduddin文档中陈述法律的方式也许是奇怪的,但是事实证明,要求return并不是一个严重的问题。cotraverse getConst . Const是一个默认的实现return/ pure来讲Distributive,并自distributives / representables有固定的形状,即实现是独一无二的。
duplode

Answers:


4
  • 每个Applicative代表其类型实参元素的“固定大小”容器的实例都是StrongApplicative
  • StrongApplicative存在发生次数a可以变化的实例

谁能想到反驳这些猜想的反例,或一些令人信服的论证,证明它们是真还是假?

我不确定第一个猜想,根据与@AsadSaeeduddin的讨论,这可能很难证明,但第二个猜想是正确的。要了解原因,请考虑StrongApplicative法律husk . unhusk == id;也就是说,对于所有x :: f ()husk (unhusk x) == x。但是在Haskell, unhusk == const (),所以法律是等于说所有的x :: f ()husk () == x。但这反过来意味着只能存在一个不同的type值f ():如果有两个值x, y :: f (),则x == husk ()and husk () == y,所以x == y。但是,如果只有一个可能的f ()值,则f必须具有固定的形状。(例如data Pair a = Pair a a,对于type Pair (),只有一个值是Pair () (),但是,type Maybe ()或存在多个值[()]。)husk . unhusk == id表示f必须具有固定的形状。


嗯 是否真的很清楚,在存在奇特的GADT和其他东西的情况下,“只能存在一个类型的不同值f ()”是否意味着“出现的次数a不能改变”?
丹尼尔·瓦格纳

@DanielWagner事实证明,“出现的次数a不能改变”对于一个StrongApplicative实例来说并不是一个充分的条件。例如,data Writer w a = Writer (w,a)具有不变的多重性a,但不是StrongApplicative。实际上,您需要函子的形状是不变的,我相信这是f ()成为单例的结果。
布拉德恩

我不确定我是否知道这有什么关系。在回答中,在确认第二个猜想的同时,您认为“强适用性”表示“一个不同f ()”表示“发生的次数a不能改变”。我反对这一论点的最后一步显然是不正确的。例如考虑data Weird a where One :: a -> Weird a; None :: Weird Bool。有一个不同的type值Weird (),但是不同的构造函数a内部包含不同数量的。(这里不是一个完整的反例,因为Functor很难,但是我们怎么知道这
Daniel Wagner

@DanielWagner好的一点Weird ()是单例,但不是固定形状。但Weird不是Functor,因此StrongApplicative无论如何也不能。我猜想相关的猜想是:如果fFunctor,是否f ()为单身意味着f形状固定?我强烈怀疑这是真的,但正如您所指出的,我实际上还没有任何证据。
布拉德恩

5

我们至少可以否定回答以下问题之一:

每个表示其类型实参元素的“固定大小”容器的Applicative都是StrongApplicative的实例

实际上StrongApplicative,原始问题中合法的例子之一是错误的。作家的适用性Monoid => (,) m不是StrongApplicative,例如husk $ unhusk $ ("foo", ()) == ("", ()) /= ("foo", ())

同样,固定大小容器的示例:

data Strange a = L a | R a

固定多重性1的定义不是很强的适用性,因为如果我们定义husk = Leftthen husk $ unhusk $ Right () /= Right (),反之亦然。一种等效的查看方法是,这仅适用于您选择on上的monoid的作者Bool

因此,存在不存在的“固定大小”应用程序StrongApplicative。所有StrongApplicatives是否具有固定大小仍有待观察。


5

让我们以可表示的仿函数作为“固定大小容器”的定义:

class Representable f where
    type Rep f
    tabulate :: (Rep f -> a) -> f a
    index :: f a -> Rep f -> a

实数Representable有一些定律和超类,但是出于这个答案的目的,我们实际上只需要两个属性:

tabulate . index = id
index . tabulate = id

(好的,我们还需要遵守法律instance StrongApplicative ((->) r)。简单易行,您已经同意存在。)

如果我们采用这个定义,那么我可以确认这个猜想1:

每个Applicative代表其类型实参元素的“固定大小”容器都是的[守法]实例StrongApplicative

是真的。就是这样:

instance Representable f => Applicative f where
    zip (fa, fb) = tabulate (zip (index fa, index fb))
    husk = tabulate . husk

instance Representable f => OpApplicative f where
    unzip fab = let (fa, fb) = unzip (index fab) in (tabulate fa, tabulate fb)
    unhusk = unhusk . index

instance Representable f => StrongApplicative f

有很多的法律证明,但我会只专注于四大该StrongApplicative插件-你可能已经相信引入药粥ApplicativeOpApplicative,但如果你不这样做,他们的证据看起来就像下面的那些(依次看起来非常相似)。为了清楚起见,我将使用zipfhuskf等的功能实例,并且ziprhuskr等为表现的情况下,这样你就可以跟踪哪个是哪个。(这样可以很容易地验证我们没有将我们要证明的东西当作假设!unhuskf . huskf = id证明时可以使用unhuskr . huskr = id,但是unhuskr . huskr = id在相同的证明中假设是错误的。)

每个定律的证明基本上以相同的方式进行:展开定义,删除Representable给您的同构,然后对功能使用类似的定律。

unhuskr . huskr
= { def. of unhuskr and huskr }
(unhuskf . index) . (tabulate . huskf)
= { index . tabulate = id }
unhuskf . huskf
= { unhuskf . huskf = id }
id

huskr . unhuskr
= { def. of huskr and unhuskr }
(tabulate . huskf) . (unhuskf . index)
= { huskf . unhuskf = id }
tabulate . index
= { tabulate . index = id }
id

zipr (unzipr fab)
= { def. of unzipr }
zipr (let (fa, fb) = unzipf (index fab) in (tabulate fa, tabulate fb))
= { def. of zipr }
let (fa, fb) = unzipf (index fab) in tabulate (zipf (index (tabulate fa), index (tabulate fb)))
= { index . tabulate = id }
let (fa, fb) = unzipf (index fab) in tabulate (zipf (fa, fb))
= { def. of (fa, fb) }
tabulate (zipf (unzipf (index fab)))
= { zipf . unzipf = id }
tabulate (index fab)
= { tabulate . index = id }
fab

unzipr (zipr (fa, fb))
= { def. of zipr }
unzipr (tabulate (zipf (index fa, index fb)))
= { def. of unzipr }
let (fa', fb') = unzipf (index (tabulate (zipf (index fa, index fb))))
in (tabulate fa', tabulate fb')
= { index . tabulate = id }
let (fa', fb') = unzipf (zipf (index fa, index fb))
in (tabulate fa', tabulate fb')
= { unzipf . zipf = id }
let (fa', fb') = (index fa, index fb)
in (tabulate fa', tabulate fb')
= { def. of fa' and fb' }
(tabulate (index fa), tabulate (index fb))
= { tabulate . index = id }
(fa, fb)

目前正在思考:instance StrongApplicative f => Representable f where type Rep f = forall x. f x -> xindex简单。我还没有解决这个问题tabulate,但似乎非常接近。
丹尼尔·瓦格纳

在与@AsadSaeeduddin的讨论中,我也设法找到了相同的StrongApplicative实例,但是无法证明法律。恭喜您解决了!我尽力做到了Representable给出的实例StrongApplicative,但是想不出一个好的Rep类型-我很好奇,您如何forall x. f x -> x实现这一目标?
布拉德恩

@bradrn回想一下,假设是这些东西在元素上插入了一组固定的“孔”。然后,类型forall x. f x -> x函数就是那些选择孔并在该孔中返回值的函数。(并且,在考虑如何实现的同时tabulate,我对的类型提出了异议unhusk;有关详细信息,请参阅问题本身的评论。)
Daniel Wagner

谢谢@DanielWagner!那是一个非常聪明的方法-我不会想到的。
布拉德恩

尝试实施它之后,我认为我无法确信它forall x. f x -> x会像Rep。我的理由是,使用这个Rep,你可以写index任何类型的,不只是StrongApplicative那些-所以我怀疑forall x. f x -> x可能是过于笼统。
布拉德恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.