在haskell中故意定义无限类型

Posted

技术标签:

【中文标题】在haskell中故意定义无限类型【英文标题】:Deliberately defining infinite type in haskell 【发布时间】:2012-03-22 22:14:51 【问题描述】:

我想定义似乎需要无限类型的东西。

必需:一个函数“eat”,它吃掉它的所有参数,除了“3”,它返回 3

eat 3 = 3
eat x = eat

所以基本上像“eat (+) foldl (Just 5) 3”这样的任意表达式的计算结果为 3。但这里的问题是吃的类型。那应该是什么?

我最接近运行代码的是:

newtype Rec = MakeRec (Int -> Rec)

eat :: Int -> Rec
eat x = MakeRec eat


instance Show Rec where
     show _ = "EAT"

这适用于“吃 6”,但不适用于“吃 6 7”,如果我将 (eat 3 = 3) 放在它的定义中,它就不起作用。

我不确定这在 Haskell 中是否可行。 (用什么论据来证明这是不可能的?)

更新:如以下解决方案所述,编译时需要类型信息,以便编译器可以知道“eat foldl 3 foldl”是否无效。所以,这个问题的精确解决方案是不可能的。

【问题讨论】:

【参考方案1】:

这是不可能的。 Haskell 明确禁止无限类型(不是数据类型),很容易生成需要它们的代码,从而产生错误(例如,尝试let foo = (42, foo) in foo)。

当然,您可以使用 newtypedata 创建它们,就像您所做的那样,但是您必须显式地将值包装和解开构造函数。

这是一个明确的设计决策:对于无限类型,必须允许许多我们希望编译器拒绝的明显错误的表达式,并且由于允许更多的程序,许多以前明确类型的程序会变得模糊类型,1 需要显式类型注释。因此做出了权衡:要求您明确说明无限类型的相当罕见的用途,以换取从类型系统中获得比我们其他方式更多的帮助。

也就是说, 有一种方法可以使用类型类来定义类似于您的 eat 函数的东西,但是只有当您给它一个 3 时它才能停止:您是否给它是否为 3 只能在运行时确定,类型在编译时确定。然而,这里有一个重载值,它既可以是 Integer,也可以是一个函数,它只是吃掉了它的参数:

class Eat a where
    eat :: a

instance Eat Integer where
    eat = 3

instance (Eat r) => Eat (a -> r) where
    eat _ = eat

问题是你需要在使用它时精确地指定类型:

*Main> eat 1 foldr ()

<interactive>:6:1:
    Ambiguous type variable `t0' in the constraint:
      (Eat t0) arising from a use of `eat'
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: eat 1 foldr ()
    In an equation for `it': it = eat 1 foldr ()
*Main> eat 1 foldr () :: Integer
3

这是因为eat 1 foldr () 可以是Integer,但也可以是另一个函数,就像我们在同一个表达式中使用eat 1eat 1 foldr 作为函数一样。同样,我们获得了灵活的类型,但必须明确指定我们想要返回的类型。

1 考虑类型类重载,就像重载的数字文字(42 可以是任何作为 Num 实例的类型)。

【讨论】:

haskell 中没有无限类型是可以的。我想知道这里是否有一个技术上不使用无限类型但仍然有效的解决方法 我在您发表评论时扩展了我的答案;我希望它有助于回答这个额外的问题:) 所以,eat 总是返回 3,并且可以吃任何类型 (a->(b-> .. Integer)) 我可以在这里设置“eat n = n”,其中 n 是一个数字,否则“eat _ = eat”,这样在编译时“eat 2 foldl”在评估时是不正确的到 "2 foldl" 而 "eat foldl 2" 正确计算为 2 ???? 以这种方式特别处理Integer 参数在技术上是可行的,但它必须使用相当脆弱且非常神秘的类型破解(准确地说是TypeEq),并且它' d 必须是 eat (2 :: Integer) foldl,同样是因为数字重载。

以上是关于在haskell中故意定义无限类型的主要内容,如果未能解决你的问题,请参考以下文章

Haskell中的两个无限数据结构之间是不是可以进行相等测试?

Haskell中无限列表的执行部分?

Haskell中Traversable冒泡排序中的无限循环

术语:在 Thompson 的书中,Haskell 中“类型表达式”的精确定义是啥?

在 haskell -> TRIE 中使用自定义递归数据类型

为啥这个 Haskell 代码可以成功地处理无限列表?