haskell - 类型缩减无限循环

标签 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类型家庭应该照顾不可约的条款,但我显然遗漏了一些东西。但是什么?

最佳答案

类型族评估并不懒惰,所以 If c t f将评估所有 c , t , 和 f . (事实上​​,类型族的求值顺序现在根本没有真正定义。)所以难怪你最终会陷入无限循环——你总是求值Simplify (op (Simplify x) (Simplify y))。 , 即使那是 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)

这个想法是:
  • Simplify1做了一步简化。
  • SimplifyFix需要x及其一步简化x' ,检查它们是否相等,如果不相等,则进行另一步简化(从而找到 Simplify1 的不动点)。
  • Simplify刚开始SimplifyFix联系 Simplify1 .

  • 由于类型族模式匹配是惰性的,SimplifyFix正确延迟评估,防止无限循环。

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

    关于haskell - 类型缩减无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39396195/

    相关文章:

    haskell - Haskell 中检测循环列表的能力会破坏该语言的任何属性吗?

    haskell - Emacs 中的 Goto 定义 - Haskell 模式

    c - while循环变量更新

    reflection - Haskell:为什么要进行类型检查?

    python - 提供与 Python 3.6 变量注释的向后兼容性

    python - 如何接受文件或路径作为python中方法的参数

    haskell - foldr groupBy 实现的类型错误

    haskell - 如何针对多个解析器构建包

    java - 初学者 : Number Guessing Game

    c++ - 错误 : Infinite-loop when loading elements into vector