Haskell 在aeson中,FromJSON1和ToJSON1用于什么?

Haskell 在aeson中,FromJSON1和ToJSON1用于什么?,haskell,typeclass,aeson,higher-kinded-types,Haskell,Typeclass,Aeson,Higher Kinded Types,Aeson提供和类型类。这些类似于模块中定义的和类 我对Eq1和Show1类的理解是,它们需要能够在不使用扩展(如FlexibleContexts和不可判定实例的情况下表达对转换器参数的约束 Data.Functor.Classes模块中的文档示例如下: T :: (* -> *) -> * -> * eq1 :: (Eq1 h, Eq a) => h a -> h a -> Bool 假设我们有一个充当转换器的数据类型:T。例如,让它同构于Identit

Aeson提供和类型类。这些类似于模块中定义的和类

我对
Eq1
Show1
类的理解是,它们需要能够在不使用扩展(如
FlexibleContexts
不可判定实例
的情况下表达对转换器参数的约束

Data.Functor.Classes
模块中的文档示例如下:

T :: (* -> *) -> * -> *
eq1 :: (Eq1 h, Eq a) => h a -> h a -> Bool
假设我们有一个充当转换器的数据类型:
T
。例如,让它同构于
IdentityT

data T f a = T (f a)
T
的类型如下:

T :: (* -> *) -> * -> *
eq1 :: (Eq1 h, Eq a) => h a -> h a -> Bool
如果存在
f
Eq1
实例,则在编写
tf
Eq1
实例时可以使用它:

instance Eq1 f => Eq1 (T f) where
  liftEq :: (a -> b -> Bool) -> T f a -> T f b -> Bool
  liftEq eq (T fa1) (T fa2) = liftEq eq fa1 fa2
如果我们有一个用于
f
Eq1
实例,一个用于
a
Eq
实例,并且上述
tf
Eq1
实例在范围内,我们可以很容易地为
tfa
编写
Eq
实例:

instance (Eq1 f, Eq a) => Eq (T f a) where
  (==) :: T f a -> T f a -> Bool
  (==) = eq1
eq1
的类型定义如下:

T :: (* -> *) -> * -> *
eq1 :: (Eq1 h, Eq a) => h a -> h a -> Bool
在我们上面的例子中,
h
变为
tf
,因此
eq1
的类型可以认为如下:

eq1 :: Eq a => T f a -> T f a -> Bool

现在,
Eq1
Show1
等类就有了意义。它似乎使为变压器编写
Eq
Show
等实例变得更容易

但是,我想知道Aeson中使用了哪些类型的
FromJSON1
ToJSON1
?我很少有我想从JSON转换的变压器

我最终改为JSON的大多数数据类型都是普通类型(不是类型构造函数)。也就是说,类型为
*
。我还使用了类似于
的类型,可能
带有一种
*->*


然而,我不认为我经常为转换器创建
ToJSON
FromJSON
实例,比如上面的
t
。什么是经常用于进出JSON的转换器?我是否错过了一些有用的转换器?

Eq1
提供了另一个您在本文中没有讨论过的功能:它允许您编写一个函数,在许多不同类型上调用
(==)
,而不必提前知道将在哪些类型上使用它

我将举一个玩具的例子;希望您能看穿这个示例的明显无用之处,从而了解
Eq1
为您提供了一些有趣功能的原因

假设您想要创建一个在分支因子上参数化的树,因此您可以通过子容器对其进行参数化。因此,值可能如下所示:

{-# LANGUAGE GADTs #-}
data Tree m a where
    Branch :: Tree m (m a) -> Tree m a
    Leaf :: a -> Tree m a
例如,我可以得到具有
树对
的二叉树、具有
树三叉
的三叉树、具有
树三叉
的手指树和具有
树[]
的玫瑰树,其中
数据对a=对a
数据三叉a=三叉a
,以及
数据二叉a=两叉a |三叉a
。现在我想为此编写一个
Eq
实例。如果我们仅仅依靠
Eq
约束,我们就无法达到我们想要达到的目的。让我们试试:

instance Eq (Tree m a) where
    Leaf a == Leaf a' = a == a'
    Branch t == Branch t' = t == t'
    _ == _ = False
自然,GHC抱怨说,它不知道如何比较
a
a'
是否相等。因此,在上下文中添加
Eq a

instance Eq a => Eq (Tree m a) where ...
现在GHC抱怨说,它不知道如何比较
ma
s在
Branch
案例中的平等性。有道理

instance (Eq a, Eq (m a)) => Eq (Tree m a) where ...
还是不行!现在,
(==)::Tree ma->Tree ma->Bool
的实现在其
分支
的情况下对
(==)::Tree m(ma)->Tree m(ma)->Bool
进行递归调用,因此必须提供上下文
(Eq(ma),Eq(ma))
来进行递归调用。好的,让我们将其添加到实例上下文中

instance (Eq a, Eq (m a), Eq (m (m a))) => Eq (Tree m a) where ...
还是不行。现在递归调用必须证明更多的东西!我们真正想说的是,如果我们有
Eq b
,那么我们有
Eq(mb)
,对于所有
b
s,而不仅仅是对于用作
树的第二个参数的特定
a

instance (Eq a, (forall b. Eq b => Eq (m b))) => Eq (Tree m a) where ...
当然,这在哈斯克尔完全不是一件事。但是
Eq1
告诉我们:

instance Eq1 m => Eq1 (Tree m) where
    liftEq (==) (Leaf a) (Leaf a') = a == a'
    liftEq (==) (Branch t) (Branch t') = liftEq (liftEq (==)) t t'
    liftEq (==) _ _ = False

instance (Eq1 m, Eq a) => Eq (Tree m a) where
    (==) = eq1
这里的
Eq1 m
约束服务于我们之前要求的角色,即所有
(Eq a,Eq(ma),Eq(ma)),…)
都是可能的


ToJSON1
FromJSON1
类起着类似的作用:它们给你一个约束,你可以给它一个潜在的无限的
ToJSON
FromJSON
约束集合,这样,您就可以以数据驱动的方式选择所需的
ToJSON
FromJSON
约束,并确保其可用。

这些类是通过。可能有一个很好的答案可以从那里的讨论中提取出来(以及在相关文章中)。谢谢!这是一个很好的解释。我将不得不慢慢地经历这件事,让它真正地深入人心。在我自己的代码中,我不认为我倾向于使用包含越来越多类型构造函数的递归类型(如
数据树ma=Branch(树m(ma))
)。我得留心那些有用的地方。另外,
Eq(treemma)
现在可以用它来写吗?@illabout这个
Tree
类型和类似的东西并不是非常常见,但存在量化框是,并且需要类似的技巧。您的链接看起来密切相关,但
Eq1
具有当前存在的明显优势。Tbf,量化上下文今天确实存在。它们只是实验性地存在。