我在以下示例中遇到了不饱和类型同义词的问题:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE LiberalTypeSynonyms #-}
module TypeFamilyHackery where
data T k v a = T
type family CollectArgTypes arr where
CollectArgTypes (a -> b) = (a, CollectArgTypes b)
CollectArgTypes _ = ()
type family MapReturnType f t where
MapReturnType f (a -> b) = a -> MapReturnType f b
MapReturnType f r = f r
type MkT k v = T k v v
-- | Goal:
-- @
-- BuryT Int = T () Int Int
-- BuryT (Bool -> Int) = Bool -> T (Bool, ()) Int Int
-- BuryT (a -> b -> c) = a -> b -> T (a,(b,())) c c
-- @
type BuryT t = MapReturnType (MkT (CollectArgTypes t)) t
但这引起了The type synonym 'MkT' should have 2 arguments, but has been given 1
的抱怨。我可以为MapReturnType
专门设置MkT (CollectArgTypes t)
,但我更喜欢它的原因。
由于-XLiberalTypeSynonyms
似乎无法提供(为什么?),我可以选择让BuryT
工作吗?
答案 0 :(得分:4)
LiberalTypeSynonyms
通过内联所有“明显的”类型定义来工作。为了使您的示例有效,它必须
MapReturnType (MkT (CollectArgTypes t)) t
视为某些MapReturnType ㄊ t
ㄊ t
MapReturnType f r = f r
ㄊ
会给MkT (CollectArgTypes t) t
这是一个非常完美的完全应用的同义词,因此没问题。但是第2步是不可能的,因为MapReturnType
不是只是一个同义词。要使用MapReturnType f r = f r
,编译器首先必须确保r
不是函数类型,但它实际上无法知道这一点 - 它毕竟是一个完全自由的参数。
那么编译器实际上需要做的是,将MapReturnType
的解析以及BuryT
的解析推迟到具体的使用站点。现在,这可能非常有用,但它会打开很多蠕虫。也就是说,在程序类型的任何地方将图灵完备程序交织在一起非常容易。我认为这不值得。