我正在尝试做一些类似于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我不太清楚为什么这不起作用,如果可能的话,可以用某种方式修复它。
发布于 2018-06-29 13:23:00
首先,我要说几句:
f a,而不管f实际上是否在Wrapper类中。特别是,它还将与标准实例(如FromJSON (Vector a) )发生冲突,尽管Vector不能是Wrapper的(行为良好)实例。之所以如此,是因为Haskell的类型系统是基于一个开放世界的假设:编译器永远不能假设某个类型不在某个类中,因为至少从技术上讲,任何人都可以在以后添加该实例。Proxy。我一直认为Proxy是一种丑陋的黑客,几乎不像undefined :: T参数那样丑陋,这些参数在过去的Haskell代码中经常被使用。在新的GHC中,-XAllowAmbiguousTypes用-XTypeApplications正确地解决了这个问题;这些允许您只进行签名。
{-#语言AllowAmbiguousTypes #-}类包装器f.名称: String
然后,代替name (Proxy :: Proxy (f a)),只编写name @f。现在来看一下实际的问题:您的代码不能工作,因为标准Haskell中的类型变量总是只属于单个类型签名/类上下文,但是在定义它的代码中是不可用的。IOW,类型变量不使用与值变量相同的名称范围,这就是为什么当您提到Proxy (f a)时,编译器会将类型变量“消歧”到f0和a0。这是Haskell98的一个愚蠢的缺点,并且是由-XScopedTypeVariables扩展(连同∀ aka 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不需要上课。
https://stackoverflow.com/questions/51102411
复制相似问题