我正在玩单身人士的专业化:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
module Data.Test where
data SingBool (b :: Bool) where
STrue :: SingBool 'True
SFalse :: SingBool 'False
sing :: SingBool b -> Bool
sing SFalse = False
sing STrue = True
{-# SPECIALIZE sing :: SingBool 'False -> Bool #-}
这适用于以下内容:
singSFalse :: SingBool 'False -> Bool
singSFalse SFalse = False
我希望它能生成singSFalse _ = False
的RHS。
这种强制解压缩只是为了满足类型检查器还是在模式匹配中涉及实际的运行时开销?我想GHC并没有放弃参数的模式匹配来解释bottom
,以免增加懒惰。但在开始通过Proxy
+ SingI
- 样式类进行建模之前,我想确定。
答案 0 :(得分:2)
好的,主要回答我自己的问题:知道SingBool 'False
只有一个居民是不足以让GHC摆脱模式匹配,因为我们可以像singSFalse (error "matched")
那样调用函数,例如底部总是另一个居民。
因此,专门化(例如基于具体TypeApplication
s的内联)在Haskell(懒惰,非整体)w.r.t中与单例(将这些类型的应用程序转换为可能的常量值应用程序)不能很好地协同工作。零成本抽象。
但是,通过使用带代理的SingI
- 样式类(例如singByProxy
),我们没有相同的问题:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
module Data.Test where
import GHC.Exts (Proxy#)
class SingIBool (b :: Bool) where
sing :: Proxy# b -> Bool
instance SingIBool 'False where
sing _ = False
instance SingIBool 'True where
sing _ = True
refurbulate :: SingIBool b => Proxy# b -> Int
refurbulate p
| sing p = 0
| otherwise = 1
专精化refurbulate @(Proxy# 'False)
不仅会被实现为const False
,也不会在价值级别传递任何Proxy#
参数,因此它更像是coerce False :: Proxy# -> Bool
。整齐!但是,我不能在现实世界中使用单身人士:(
回顾一下为什么单身人士失败(为了得到优化)和类型工作:
通过专门化类型类实例,我们可以了解sing
的RHS,从中我们可以推导出整体性。
通过专门化单例,我们可以知道参数评估的值,如果评估终止。
了解类型类方法x :: ()
的规范RHS比仅知道参数x :: ()
只能评估非总计,懒惰(例如Haskell)设置中的一个值更具信息性。