haskell - 这个多参数类型类可以简化吗?

标签 haskell typeclass contravariance

我创建此类型类是为了使 Divisible 仿函数(“Applicative 的逆变模拟”- https://hackage.haskell.org/package/contravariant-1.2/docs/Data-Functor-Contravariant-Divisible.html)以几乎相同的方式与多参数函数一起使用作为 Applicative 仿函数。

这个想法是你写unFunc |$|法|*|面子书 |*| fc,其中:

unFunc :: z -> (a, (b, (c, ())))
fa :: f a
fb :: f b
fc :: f c

得到一个 f z,对于一些 Divisible 仿函数 f|$|divide 来自 Data.Functor.Contravariant.Divisible|*| dApply 来 self 下面的代码:

{-# LANGUAGE FlexibleContexts
           , FlexibleInstances
           , FunctionalDependencies
           , MultiParamTypeClasses
           , TypeFamilies
           , UndecidableInstances
  #-}

import Control.Applicative ((<$>), (<*>), Applicative)
import Data.Functor.Contravariant.Divisible
  ( Divisible(divide, conquer)
  , divided
  )

result :: (b -> c) -> (a -> b) -> (a -> c)
result = fmap

class Divisible f => DivisibleApply f t z r | f t z -> r, r t -> f, r t -> z
  where dApply :: (f (a, t) -> f z) -> f a -> r

instance Divisible f => DivisibleApply f () z (f z)
  where dApply = (. flip divided conquer)

instance DivisibleApply f b z r' => DivisibleApply f (a, b) z (f (a, b) -> f z)
  where dApply = flip (result.result) divided

这确实有效!但是 DivisibleApply 类似乎太复杂了。我实际上只是在 t 参数上“切换”,我实际上想在 fz 中完全多态;它们只是类参数,因为实例需要根据它们实例化 r

最初我尝试使用类型族;该类只有一个参数 tr 的角色由关联类型承担。我遇到的问题(以及许多其他变体)是,即使我可以让它接受类和实例,将它应用于多个参数也会因类型变量不明确而失败。我相信这是因为我没有与 haskell 沟通我一直在使用相同的 f

是否有可能为 dApply 返回更简单的类型,同时仍然保持 unFunc |$|法|*|面子书 |*| fc 用法?

(我的最终目标是使用它来创建一个包含两者 ApplicativeDivisible 的类型类;给定一对函数 func::a -> b -> c -> zunFunc::z -> (a, (b, (c, ()))) 应该是可以制作一个函数 f a -> f b -> f c-> f z 只知道 f 是协变或逆变,而不知道是哪个。因此我为什么要镜像Applicative用法的结构

最佳答案

我认为这里的问题是“Applicative 样式”非常适合 Divisible 的组合方式,因此您没有自然类型如果您坚持完全使用 unFunc |$| ,则给出您的中间结果法|*|面子书 |*| fc 格式。毕竟最直接的写法是

unFunc `contramap` (fa `divided` (fb `divided` (fc `divided` conquered)))

它以与 Applicative 风格完全相反的方式关联。

强制将其转换为该格式会导致代码采用在我看来类似于 Text.Printf 的可变长度参数列表重载技巧 - 这是您正在反对的明确信号类型。

相反,我建议稍微更改用法,以便它可以适应 ApplicativeDivisible 的更自然类型。也许是这样的:

func |$| fa |*| fb |*| fc |!| unFunc

显示相似性的示例代码(我留给你实际统一它们。)我还更改了 unFunc 的类型以更好地适应这种用法。

import Data.Functor.Contravariant
import Data.Functor.Contravariant.Divisible
import Control.Applicative

(|$|) :: Divisible f => t -> f a -> f a
f |$| fa = fa -- For Divisibles, this end does nothing

(|*|) :: Divisible f => f a -> f b -> f (a, b)
fa |*| fb = divided fa fb

(|!|) :: Contravariant f => f b -> (a -> b) -> f a
fz |!| unFunc = contramap unFunc fz

(<!>) :: Applicative f => f z -> t -> f z
fz <!> _ = fz -- For Applicatives, this end does nothing

-- These two functions have the same type except for one using Divisible and the other Applicative

divide3 :: Divisible f => (a -> b -> c -> z) -> (z -> ((a, b), c)) -> f a -> f b -> f c -> f z
divide3 func unFunc fa fb fc = func |$| fa |*| fb |*| fc |!| unFunc

apply3 :: Applicative f => (a -> b -> c -> z) -> (z -> ((a, b), c)) -> f a -> f b -> f c -> f z
apply3 func unFunc fa fb fc = func <$> fa <*> fb <*> fc <!> unFunc

我还可以看到另一种方法,您可以删除初始 |$| 部分并使用 ApplicativeDivisible 更好地支持成对组合这一事实 支持函数的应用,因此您可以对 Applicative 使用与我上面用于 Divisible 相同的方法。

关于haskell - 这个多参数类型类可以简化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28737332/

相关文章:

c# - IComparable 不需要逆变?

c# - 为什么 C# 4.0 的协变/逆变仅限于参数化接口(interface)和委托(delegate)类型?

haskell - 是否有一系列 Haskell 函数用于对应用元组进行排序?

android - Android上的Haskell解释器?

scala - 在类型类中,如何使用额外的参数来改变操作?

haskell - 简单语句中的模糊类型 Haskell

performance - Haskell 中的素筛

haskell - 从镜头列表创建遍历

haskell - GADT 类型的奇怪类型推理行为(对于固定长度向量)

c# - 将子类分配给接口(interface),涉及泛型和协变