简体   繁体   English

类型类中的详尽性检查以提升类型

[英]Exhaustiveness check in typeclasses for promoted types

I have promoted type Nat = Suc Nat | Zero 我提升了类型Nat = Suc Nat | Zero Nat = Suc Nat | Zero and I want to make a typeclass class C (a :: Nat) b . Nat = Suc Nat | Zero ,我想制作一个类型class C (a :: Nat) b Is there a way to convince GHC that instance C Zero b and instance C (Seq x) b covers all cases and therefore I don't need to explicitly declare C as a constraint whenever I use the class' methods. 有没有办法让GHC确信instance C Zero binstance C (Seq x) b涵盖了所有情况,因此,每当我使用类的方法时,我都不需要显式声明C作为约束。 Here is some code: 这是一些代码:

{-# 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

Edit: A related question would be, given the commented out instance if C , why is it when I say noGreet "hi" to the repl I get an exception and not Just "hi" . 编辑:给定一个注释掉的实例C ,一个相关的问题是,为什么当我对repl说noGreet "hi"我得到一个异常,而Just "hi"

noGreet :: forall a . a -> Maybe a

Parametricity says the only definable values of this type are things like 参数表示这种类型的唯一可定义值是

noGreet x = Just x
noGreet x = Nothing
noGreet x = undefined
noGreet x = x `seq` Just x
...

We can't make any choices that depend on the type a , like " Nothing if a is Char otherwise Just x ". 我们不能依赖于任何类型选择a ,像“ Nothing ,如果aChar ,否则Just x ”。

"Tricking the type checker" is a red herring, since what is preventing you from writing such a function is not the type checker, but the fact that information about the type a is simply not available at all at runtime. “欺骗类型检查器”是一个麻烦,因为阻止您编写此类函数的不是类型检查器,而是有关类型a信息在运行时根本不可用的事实。


When you used IncoherentInstances in 在以下情况下使用IncoherentInstances

noGreet :: forall a . a -> Maybe a
noGreet x = f (NProxy :: NProxy (GetNum a)) x

the compiler had to choose which C instance to use for the call to f , since there is no context provided in the type of noGreet . 编译器必须选择使用哪个C实例来调用f ,因为没有提供noGreet类型的noGreet Naturally the only one that applied was 自然,唯一适用的是

instance C n b where f = error "This should not have been reached using GetNum."

as the other two instances are too specific to use when we know nothing about a . 因为其他两个实例太具体了,当我们对a

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM