【问题标题】:Reordering type parameters in Haskell在 Haskell 中重新排序类型参数
【发布时间】:2020-02-06 00:08:29
【问题描述】:

我有一个关于类型参数的问题,我认为最好用一个例子来表达。这段代码

newtype Triple a b c = T (a,b,c)

instance Functor (Triple a b) where
    fmap f (T (x, y, z)) = T (x, y, (f z))

将三元组表示为第三个变量中的函子。

  1. 如何将它们转换为第二个变量中的函子?
  2. 如何将实际元组(不是我的新类型)转换为仿函数?

一般的问题是:假设我有一个参数类型m a b c d e,我如何表达固定一个参数得到的参数类型m a b d e?或者等价的,如何表示将任意参数设为最后一个得到的参数类型m a b d e c

编辑:我的意思可能不太清楚,所以我想澄清一下:Triple 有一种* -> * -> * -> *。因此,我可以对两种类型进行部分评估,以获得类似 * -> * 的东西,它可能是 Functor 或其他一些参数化类。这种评估很容易在前两个参数上进行,但原则上可以在任何两个参数上进行,我在问如何做到这一点。这实质上是在类型级别上要求flip

作为一个具体的用例,我可以有三个参数化类 Functor、Foo 和 Bar,我希望 (Triple _ b c) 成为 Functor, (Triple a _ c) 成为 Foo,并且 (Triple a b _ ) 成为 Bar(对于所有 a、b、c)。那么Triple a b c 将是FunctorFooBar。您可能会考虑编写这些单参数类型 a -> Triple a b cb -> Triple a b cc -> Triple a b c,但当然这种文字符号表示映射类型。

Edit2:在 stackoverflow 上发布问题之前,我总是尝试将其剥离到其抽象核心,但这似乎掩盖了我真正想要的东西。所以现在可以找到这个问题的具体变体here

【问题讨论】:

  • 你可能认为使用TypeSysnonymInstances ghc 扩展你可以做type TripleSynonym a c b = (a, b, c) 然后instance Functor (TripleSynonym a c) 但不是:在这种情况下,ghc 不允许你部分评估类型。

标签: haskell types


【解决方案1】:

在这种特定情况下,您可能会通过使用镜头获得所需的东西。

overall the functions in the tuple module (_1, _2, _3 etc.) 的组合使您能够将函数提升到更多元组位置,而不仅仅是最右边的位置。

编辑添加示例。

假设我们有这个元组。

(1, "Foo", True)

我们想(+ 1) 到它的第一个位置的值。

> import Control.Lens (over, _1)
> over _1 (+ 1) (1, "Foo", True)
(2,"Foo",True)

或将第二个位置的字符串大写

> import Data.Char (toUpper)
> import Control.Lens (over, _2)
> over _2 (map toUpper) (1, "Foo", True)
(1,"FOO",True)

或者也许我们想将 bool 翻转到第三个位置

> import Control.Lens (over, _3)
> over _3 not (1, "Foo", True)
(1,"Foo",False)

【讨论】:

  • 您愿意举个例子吗?这似乎是一个足够的抽象层次,但我不熟悉镜头。
  • 当然,添加到答案中。
  • 谢谢!但这在类型级别上是如何工作的?本质上我想改变三元组的类型。
  • Hrm,我给你的是如何将函数提升到不同的元组位置。在我看来,这将很有用,因为它有点在你喜欢的任何位置制作元组函子。我想,我需要更多地了解你想要做什么,以提供更多帮助。你有什么理由不得不使用 Functor?
  • 啊,我也意识到,在我的所有示例中,您都看不到可以更改仓位的类型。即:over _1 @(,,) 的类型应为 (a -> d) -> (a, b, c) -> (d, b, c)
【解决方案2】:

这就是新类型的用途。您将现有类型包装在新类型中,让您在类型级别对其执行不同的操作,同时保持值级别不变。例如:

newtype SecondTriple a b c = SecondTriple (a, c, b)

instance Functor (SecondTriple a b) where
  fmap f (SecondTriple (x, z, y)) = SecondTriple (x, f z, y)

如果你愿意,你可以包装 Triple 而不是包装 (,,),但当然你不能使用 Triple 的 Functor 实例,所以它没有多大帮助。

【讨论】:

  • 这个建议有两个问题: 1. 如果我为具有 n 个参数的类型的所有排列引入一个新类型,这将给我很多新类型(n!); 2.我实际上可能希望一个元组成为一个仿函数。第一个论点,并在其他一些类wrt。第二个参数。
【解决方案3】:

函子有种类Type -> Type,所以Triple :: Type -> Type -> Type -> Type 本身不是函子;只有ab 2 种类型的接近饱和的部分应用程序Triple a b 可以是函子。

Triple,然而,一个“三函子”的例子,你可以自己定义。

class Trifunctor p where
    trimap :: (a -> x) -> (b -> y) -> (c -> z) -> p a b c -> p x y z
    -- There are only so many synonyms for first, second, etc
    map13 :: (a -> x) -> p a b c -> p x y z
    map13 f = trimap f id id
    map23 :: (b -> y) -> p a b c -> p x y z
    map23 f = trimap id f id
    map33 :: (c -> z) -> p a b c -> p x y z
    map33 f = trimap id id f

instance Trifunctor Triple where
    trimap f g h (Triple x y z) = Triple (f x) (g y) (h z)

模式概括; n 类型的乘积是 n-functor。

【讨论】:

  • 谢谢,我说的不准确。我想说“Triple a _ c”是函子,“Triple a b _”是 foo,“Triple _ b c”是 bar。
  • 你不能。所有类型类都有类型* -> Constraint,其中* 是某种特定类型。类型构造函数就像函数一样被柯里化,所以 Triple a _ c 不是生成 kind 的有效部分应用程序。
  • 更具体地说,您可以说,例如 Triple 在它的第二个参数中是 functorial,“foo-like”在它的第三个,第一个是“酒吧式”。 (对于一些具体的例子,双函子的两个参数都是函子,而函子的第一个是反函子,第二个是函子。)你想要什么,就需要一些类型类组合的概念,据我所知知道,Haskell 没有这样的东西。 (我也不知道缺少是由于语言的限制,还是只是缺少实现它的库。)
  • (或者更确切地说,Triple 可能是某个类型类的 instance,描述了它的实例的 bar-likeness、functoriality 和 foo-likeness。)
猜你喜欢
  • 2012-04-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 2019-06-25
  • 2017-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多