gpt4 book ai didi

haskell多态函数评估错误

转载 作者:行者123 更新时间:2023-12-02 11:23:53 24 4
gpt4 key购买 nike

以下代码无法编译:

foo :: Num a => (a -> a) -> Either Integer Double -> Either Integer Double
foo f x = case x of
Left i -> Left $ f i
Right d -> Right $ f

并给出以下错误:

Couldn't match type `Integer' with `Double'
Expected type: Either Integer Double
Actual type: Either Integer a
In the expression: Right $ f d
In a case alternative: Right d -> Right $ f d

这是 this question 的后续问题,使用RankNTypes解决了这个问题:

(forall a. Num a => a -> a)

但答案没有说什么。我想知道:

  • 此错误的根本原因是什么?最终结果只会是 case 分支之一,f 不会同时输入两种类型,只要 f::Num 就应该检查 f 的类型a => (a -> a),Integer -> Integer 或 Double -> Double 应该可以工作,有人可以详细说明为什么这会导致错误吗?

  • 还有其他方法可以修复该错误吗?为什么 RankNTypes 会修复该错误?这让我印象深刻,就像我前几天遇到的单态限制错误一样,但启用它并不能帮助我解决这个问题,而且显式类型注释也不起作用。

最佳答案

根本原因是,根据您的原始定义,a太一般了。考虑:

foo :: Num a => (a -> a) -> Either Integer Double -> Either Integer Double
foo f x = case x of
Left i -> Left $ f i

此时,类型检查器遇到了麻烦,因为 Left $ f i 的类型必须是Either Integer Double ,因此表达式 f i必须是Integer 。但是您说调用者可以传递将数字类型映射到其自身的任何函数。例如,您的类型签名允许传递 Double -> Double功能。显然,这样的函数可能永远不会导致 Integer ,因此应用f此处输入得不好。

OTOH,如果您使用排名较高的类型的解决方案,您将无法传递任何适用于特定类型的函数 - 只能传递适用于所有数字类型的函数。例如,您可以传递 negate ,但不是((1::Integer)+) 。这绝对有道理,因为您也将相同的函数应用于 Double其他情况下的值。

因此,为了回答你的第二个问题,根据你的代码,排名较高的类型解决方案是正确的。显然你只想传递像 negate 这样的函数如果你想将其应用到 Integer和一个 Double .

底线:与

f :: (a -> a) -> b

你可以传递像 id 这样的函数, tail , reverse , ((1::Int)+) 。与

f :: (forall a. a -> a) -> b

您只能传递具有确切类型签名的函数forall a. a->a (取模类型变量重命名)如id ,但上面提到的其他都没有。

关于haskell多态函数评估错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21107020/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com