详尽的检查类型提升类型的类型

时间:2017-02-14 14:23:25

标签: haskell typeclass non-exhaustive-patterns type-promotion

我已经提升了类型Nat = Suc Nat | Zero,我想创建一个类型类class C (a :: Nat) b。有没有办法说服GHC instance C Zero binstance C (Seq x) b涵盖所有情况,因此每当我使用类'方法时,我都不需要明确声明C作为约束。这是一些代码:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
-- Some of these may not be necessary for the particular snippet.

data Nat = Zero | Suc Nat
-- TypeApplications, I know. I am traditional.
data NProxy :: Nat -> * where
  NProxy :: NProxy n

class C (a :: Nat) b where
  f :: NProxy a -> b -> Maybe b

instance C Zero b where
  f _ _ = Nothing
instance C (Suc a) b where
  f _ = Just
-- instance C n b where
--   f = error "This should not have been reached using GetNum."


class C1 a where
  f1 :: a -> Maybe a

instance C1 a where
  f1 = Just

type family GetNum a :: Nat where
  GetNum Char = (Suc Zero)
  GetNum Int = Suc (Suc Zero)
  GetNum [x] = Suc (GetNum x)
  GetNum a = Suc Zero

-- Error:
-- • No instance for (C (GetNum a) a) arising from a use of ‘f’
-- • In the expression: f (NProxy :: NProxy (GetNum a)) x
--   In an equation for ‘noGreet’:
--       noGreet x = f (NProxy :: NProxy (GetNum a)) x
noGreet :: forall a . a -> Maybe a
noGreet x = f (NProxy :: NProxy (GetNum a)) x

-- This one works fine though.
dumb :: a -> Maybe a
dumb = f1

编辑:相关的问题是,如果C注释掉实例,为什么当我对repl说noGreet "hi"时我得到的是异常,而不是Just "hi"。< / p>

1 个答案:

答案 0 :(得分:4)

noGreet :: forall a . a -> Maybe a

Parametricity说这种类型唯一可定义的值是

之类的东西
noGreet x = Just x
noGreet x = Nothing
noGreet x = undefined
noGreet x = x `seq` Just x
...

我们无法做出任何取决于a类型的选择,例如Nothing如果aChar,则为Just x“。

“欺骗类型检查器”是一个红色的鲱鱼,因为阻止你编写这样一个函数的不是类型检查器,而是关于类型a的信息根本不可用的事实运行时。

中使用IncoherentInstances
noGreet :: forall a . a -> Maybe a
noGreet x = f (NProxy :: NProxy (GetNum a)) x

编译器必须选择用于调用C的{​​{1}}实例,因为f类型中没有提供上下文。当然,唯一适用的是

noGreet

因为当我们对instance C n b where f = error "This should not have been reached using GetNum." 一无所知时,其他两个实例太具体而无法使用。