0

我一直在试验这个简单的 HLists 实现和一个如果 an是列表成员则hasInt返回的函数:TrueInt

{-# LANGUAGE FlexibleInstances #-}

data HNil = HNil
  deriving (Show, Read)

data HCons a b = HCons a b
  deriving (Show, Read)

class HasInt a where
  hasInt :: a -> Bool

instance HasInt HNil where
  hasInt _ = False

instance HasInt as => HasInt (HCons a as) where
  hasInt (HCons a as) =  (isInt a) || (hasInt as)

class IsInt a where
  isInt :: a -> Bool

instance IsInt Int where
  isInt _ = True

instance {-# OVERLAPPABLE #-} IsInt a where
  isInt _ = False

three = 3 :: Int

main = do
  putStrLn $ "isInt three = " ++ show (isInt three) -- True
  putStrLn $ "isInt True  = " ++ show (isInt True)  -- False
  print $ hasInt $ HCons three $ HCons True HNil    -- False ???

这没有给出预期的结果。但是,如果我改变它似乎确实有效:

    instance HasInt as => HasInt (HCons a as) where

到:

    instance (IsInt a, HasInt as) => HasInt (HCons a as) where

另一方面,如果我使用类型类函数但不包含约束,我通常希望 GHC 会抱怨,并且在这种情况下我没有得到任何此类指示。

显然,它必须与 catch-all instance 做一些事情IsInt a。如果我将Could not deduce (IsInt a) arising from a use of 'isInt' catch-all 实例替换为:

instance IsInt Bool where isInt _ = False
instance IsInt HNil where isInt _ = False

我的问题是:这是 GHC 的预期行为 - 如果没有明确的类型类约束,它会默默地使用一个包罗万象的实例吗?

4

1 回答 1

3

是的,这是预期的行为。如果你写

instance Foo a

您声明所有类型都是 的实例Foo,而 GHC相信您。

这 100% 类似于以下内容:

foo :: Int -> Bool
foo x = x > 0

即使您没有Ord Int上下文,GHC 也知道存在这样的实例。同样,在:

bar :: a -> b
bar x = {- use the Foo instance for x here -}

即使您没有Foo a上下文,GHC 也知道存在这样的实例。

于 2017-07-26T00:17:35.947 回答