Haskell 在aeson中,FromJSON1和ToJSON1用于什么?
Aeson提供和类型类。这些类似于模块中定义的和类 我对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
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,量化上下文今天确实存在。它们只是实验性地存在。