类型缩减无限循环

时间:2016-09-08 16:37:10

标签: haskell infinite-loop typechecking type-families

我的目标是从术语中删除(),如下所示:

(a, b)       -> (a, b)
((), b)      -> b
(a, ((), b)) -> (a, b)
...

这是代码:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Simplify where

import Data.Type.Bool
import Data.Type.Equality

type family Simplify x where
  Simplify (op () x) = Simplify x
  Simplify (op x ()) = Simplify x
  Simplify (op x y)  = If (x == Simplify x && y == Simplify y)
                          (op x y)
                          (Simplify (op (Simplify x) (Simplify y)))
  Simplify x         = x

然而,尝试一下:

:kind! Simplify (String, Int)

...导致类型检查器中出现无限循环。我认为If类型的家庭应该照顾不可约的条款,但我显然遗漏了一些东西。但是什么?

2 个答案:

答案 0 :(得分:10)

类型系列评估不是懒惰,因此If c t f将评估ctf的所有内容。 (事实上​​,类型族评价顺序现在还没有真正定义。)所以难怪你最终会得到一个无限循环 - 你总是评价Simplify (op (Simplify x) (Simplify y)),即使这样#&# 39; s Simplify (op x y)

你可以通过将递归和简化分开来避免这种情况,如下所示:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Simplify where

import Data.Type.Bool
import Data.Type.Equality

type family Simplify1 x where
  Simplify1 (op () x) = x
  Simplify1 (op x ()) = x
  Simplify1 (op x y)  = op (Simplify1 x) (Simplify1 y)
  Simplify1 x         = x

type family SimplifyFix x x' where
  SimplifyFix x x  = x
  SimplifyFix x x' = SimplifyFix x' (Simplify1 x')

type Simplify x = SimplifyFix x (Simplify1 x)

这个想法是:

  1. Simplify1执行简化步骤。
  2. SimplifyFix需要x及其一步简化x',检查它们是否相等,以及它们是否进行了另一个简化步骤(因此找到Simplify1)的固定点。
  3. Simplify只需拨打SimplifyFix即可从Simplify1链开始。
  4. 由于类型系列模式匹配是惰性的,SimplifyFix会正确延迟评估,从而阻止无限循环。

    确实:

    *Simplify> :kind! Simplify (String, Int)
    Simplify (String, Int) :: *
    = (String, Int)
    
    *Simplify> :kind! Simplify (String, ((), (Int, ())))
    Simplify (String, ((), (Int, ()))) :: *
    = ([Char], Int)
    

答案 1 :(得分:3)

我想我会提到,鉴于简化具有折叠结构,因此无需构建涉及一次又一次重新遍历表达式的修复点的复杂解决方案。

这样做会很好:

{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE UndecidableInstances #-}
module Simplify where

type family Simplify x where
  Simplify (op a b) = Op op (Simplify a) (Simplify b)
  Simplify x        = x

type family Op op a b where
  Op op () b = b
  Op op a () = a
  Op op a b  = op a b