gpt4 book ai didi

haskell - 在类型类中使用代理

转载 作者:行者123 更新时间:2023-12-02 06:13:42 25 4
gpt4 key购买 nike

我正在尝试做类似于 this question 的事情.

我想定义一个类型类

class Wrapper f where
wrap :: a -> f a
unwrap :: f a -> a
name :: Proxy (f a) -> String

然后定义
instance (IsString a, FromJSON a, Wrapper f) => FromJSON (f a) where
parseJSON (String s) = wrap <$> pure (fromString $ unpack s)
parseJSON invalid = typeMismatch (name (Proxy :: Proxy (f a))) invalid

但我收到一个错误说
Could not deduce (Wrapper f0) arising from a use of ‘name’                                               
from the context: (IsString a, FromJSON a, Wrapper f)
bound by the instance declaration at src/Model/Wrapper.hs:29:10-62
The type variable ‘f0’ is ambiguous

我不太清楚为什么这不起作用以及是否可以以某种方式修复它

最佳答案

首先说几点:

  • 不要定义这样的实例。此实例将匹配任何形式 f a ,无论是否f实际上是在Wrapper类(class)。特别是,它还会与标准实例(例如 FromJSON (Vector a))发生冲突。 ,即使 Vector不能是 Wrapper 的(行为端正的)实例.这样做的原因是 Haskell 的类型类系统基于一个开放世界的假设:编译器永远不能假设一个类型不在某个类中,因为任何人都可以,至少从技术上讲,以后添加实例。
  • 我建议不要使用 Proxy在新代码中。我一直在考虑Proxy一个丑陋的黑客,几乎没有 undefined :: T 丑陋在旧的 Haskell 代码中常用的参数。在新的 GHC 中,问题已由 -XAllowAmbiguousTypes 正确修复与 -XTypeApplications ;这些允许您简单地进行签名
    {-# LANGUAGE AllowAmbiguousTypes #-}
    class Wrapper f where
    ...
    name :: String

    然后代替 name (Proxy :: Proxy (f a))只写 name @f .

  • 现在到实际问题:您的代码不起作用,因为标准 Haskell 中的类型变量始终只属于单个类型签名/类上下文,但在定义它的代码中不可用。 IOW,类型变量不使用与值变量相同的名称范围,这就是为什么当您提到 Proxy (f a) 时编译器将类型变量“消除歧义”为 f0a0 .这是 Haskell98 的一个愚蠢的缺点,由 -XScopedTypeVariables 解决。扩展名(与 又名 forall 关键字一起)。以下将自行编译:
    {-# LANGUAGE ScopedTypeVariables, UnicodeSyntax #-}
    instance ∀ f a . (IsString a, FromJSON a, Wrapper f) => FromJSON (f a) where
    parseJSON (String s) = wrap <$> pure (fromString $ unpack s)
    parseJSON invalid = typeMismatch (name (Proxy :: Proxy (f a))) invalid

    正如我所说,不应该定义这样的实例。我认为你真正想要的是
    {-# LANGUAGE DataKinds, KindSignatures, TypeApplications #-}

    import GHC.TypeLits (Symbol, KnownSymbol, symbolVal)

    data Wrapper (n :: String) (a :: *)
    = Wrapper a
    | TypeMismatch String

    instance ∀ a s . (IsString a, FromJSON a, KnownSymbol s)
    => FromJSON (Wrapper s a) where
    parseJSON (String s) = Wrapper <$> pure (fromString $ unpack s)
    parseJSON invalid = TypeMismatch $ symbolVal @s Proxy

    不需要上课。

    关于haskell - 在类型类中使用代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51102411/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com