故意在haskell中定义无限类型

Kar*_*ran 10 haskell types infinite

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

必需:一个函数"吃"吃掉它除了"3"之外的所有参数,它返回3

eat 3 = 3
eat x = eat
Run Code Online (Sandbox Code Playgroud)

所以基本上像"吃(+)foldl(Just 5)3"这样的任意表达式评估为3.但这里的问题是吃的类型.应该是什么?

我得到的最接近的运行代码是:

newtype Rec = MakeRec (Int -> Rec)

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


instance Show Rec where
     show _ = "EAT"
Run Code Online (Sandbox Code Playgroud)

这适用于"吃6"而不是"吃6 7",如果我把(吃3 = 3)放在它的定义中它就不起作用.

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

更新:如下面的解决方案中所述,在编译时需要类型信息,以便编译器可以知道"eat foldl 3 foldl"是否无效.因此,这个问题的确切解决方案是不可能的.

ehi*_*ird 22

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

当然,您可以使用newtype和创建它们data,就像您一样,但是您必须明确地将值包装并拆分为构造函数.

这是一个明确的设计决策:对于无限类型,我们希望编译器拒绝的许多明显错误的表达式必须被允许,并且由于允许更多的程序,许多以前明确类型的程序将变得模糊地键入,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
Run Code Online (Sandbox Code Playgroud)

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

*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
Run Code Online (Sandbox Code Playgroud)

这是因为它eat 1 foldr ()可能是一个Integer,但它也可能是另一个函数,就像我们在同一个表达式中使用eat 1eat 1 foldr作为函数一样.同样,我们得到灵活的输入,但必须明确指定我们想要的类型.

1认为类型类重载,比如重载的数字文字(42可以是任何类型的实例Num).