【问题标题】:Non type-variable argument in the constraint for Arbitrary typeclass任意类型类的约束中的非类型变量参数
【发布时间】:2018-09-10 23:58:59
【问题描述】:

对于 Haskell Programming From First Principles 第 15 章的练习,我正在尝试基于另一个 Arbitrary 实例编写一个 Arbitrary 实例:

module AccumulateRight where

import Data.Semigroup
import Test.QuickCheck

data Validation a b = Fail a | Pass b deriving (Eq, Show)

newtype AccumulateRight a b =
    AccumulateRight (Validation a b) deriving (Eq, Show)

type TestType = AccumulateRight String [Int]

instance Semigroup b => Semigroup (AccumulateRight a b) where
    _ <> (AccumulateRight (Fail x)) = Fail x
    (AccumulateRight (Fail x)) <> _ = Fail x
    (AccumulateRight (Success a)) <> (AccumulateRight (Success b)) =
        AccumulateRight . Success $ a <> b

instance (Arbitrary a, Arbitrary b) => Arbitrary (Validation a b) where
    arbitrary = oneof [Fail <$> arbitrary, Pass <$> arbitrary]

instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
    arbitrary = AccumulateRight <$> arbitrary

semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)

type Assoc = TestType -> TestType -> TestType -> Bool

main :: IO ()
main = quickCheck (semigroupAssoc :: Assoc)

但出现以下错误:

    • Non type-variable argument
        in the constraint: Arbitrary (Validation a b)
      (Use FlexibleContexts to permit this)
    • In the context: Arbitrary (Validation a b)
      While checking an instance declaration
      In the instance declaration for ‘Arbitrary (AccumulateRight a b)’
   |
22 | instance Arbitrary (Validation a b) => Arbitrary (AccumulateRight a b) where
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

那么我在这里做错了吗?为什么我不能在这里使用现有数据的 typeclass 作为约束?

【问题讨论】:

    标签: haskell polymorphism typeclass parametric-polymorphism


    【解决方案1】:

    这是一个愚蠢的限制,在人们了解实现类型类有多么困难之前就已经设置好了。事实证明它很容易支持,所以有一个语言扩展——在错误中提到——让你这么说。你可以通过添加来开启它

    {-# LANGUAGE FlexibleContexts #-}
    

    到您文件的顶部,并且随着扩展的进行,这被认为是完全良性的。但是,在这种情况下,您不应该打开它,而应该只写

    instance (Arbitrary a, Arbitrary b) => Arbitrary (AccumulateRight a b)
    

    -- 毕竟,(Arbitrary a, Arbitrary b) 正是 Arbitrary (Validation a b) 成立的条件。

    【讨论】:

    • 您能否解释一下 FlexibleContexts 的含义以及它与此处的错误有何关系?
    • @yhylord 没什么好说的。报告说,在上下文(包括instance 上下文)中,类只能应用于(类型)变量。由于Validation a b 不是变量,因此Arbitrary (Validation a b) 不允许在实例上下文中使用——但由于a 是变量而b 是变量,Arbitrary aArbitrary b 都可以。 FlexibleContexts 扩展只是解除了这个限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多