故意在haskell中定义无限类型

故意在haskell中定义无限类型,haskell,types,infinite,Haskell,Types,Infinite,我想定义似乎需要无限类型的内容 必需:一个函数“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 wher

我想定义似乎需要无限类型的内容

必需:一个函数“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"
这对“eat 6”有效,但对“eat 6 7”无效,如果我把(eat 3=3)放在它的定义中,它就不起作用了

我不确定这在哈斯克尔是否可行。(一个人会用什么论据来证明这是不可能的?)


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

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

当然,您可以像以前那样使用
newtype
data
创建它们,但随后必须显式地在构造函数中包装和展开值

这是一个明确的设计决策:对于无限类型,我们希望编译器拒绝的许多明显错误的表达式必须被允许,而且由于允许更多的程序,许多以前类型明确的程序将变得类型模糊,1需要显式类型注释。因此,需要做一个折衷:要求您明确表示无限类型的非常罕见的用法,以换取从类型系统获得比其他方式多得多的帮助

也就是说,有一种方法可以使用TypeClass定义类似于
eat
函数的东西,但它不能仅在给它一个3时停止:是否给它一个3只能在运行时确定,类型在编译时确定。但是,这里有一个重载值,它既可以是一个
整数
,也可以是一个只吃掉其参数的函数:

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
*Main>eat 1 foldr()
:6:1:
约束中不明确的类型变量“t0”:
(Eat t0)由“Eat”的用法引起
可能修复:添加修复这些类型变量的类型签名
表达式中:eat 1 foldr()
在‘it’的方程式中:it=eat 1 foldr()
*Main>eat 1 foldr()::整数
3.
这是因为
eat 1 foldr()
可以是一个
整数
,但也可以是另一个函数,就像我们在同一表达式中使用
eat 1
eat 1 foldr
作为函数一样。同样,我们得到了灵活的类型,但必须明确指定我们想要的类型作为回报


我认为类型类重载,就像重载的数字文本一样(
42
可以是
Num
实例中的任何类型)。

haskell中没有无限类型是可以的。我想知道这里是否有一个作品在技术上不使用无限类型,但仍然有效。我扩展了我的答案,正如你发表的评论;我希望它能帮助回答这个额外的问题:)因此,eat总是返回3,并且吃任何类型(a->(b->…整数))这里我可以使它成为“eat n=n”,其中n是一个数字,否则为“eat=eat”,因此在编译时“eat 2 foldl”是不正确的,因为它的计算结果是“2 foldl”,而“eat foldl 2”正确地计算为2???从技术上讲,可以专门以这种方式处理
Integer
参数,但必须使用非常脆弱且非常神秘的类型hack(,准确地说),并且必须是
eat(2::Integer)foldl
,同样是因为数字重载。