han*_*nan 4 polymorphism haskell types ghci parametric-polymorphism
我是 Haskell 的新手,从第一原则开始阅读 Haskell。
顺便说一句,这个问题一般与本书无关,我以以下问题为例
在第 10 章,第 10.5 节,Q 5,f 部分
题:
以下是与您已经看到的非常相似的简单折叠,但每个折叠都至少有一个错误。请修复它们并在您的 REPL 中测试
f) 文件夹 const 'a' [1..5]
并且它给出了以下错误 No instance for (Num Char)来自文字“1”
只是意味着 1 不能在这里用作 Char
但我在本章中读到折叠就像文本重写器,用函数替换 cons(:) 并用累加器替换空列表,所以结果是(我缩短了列表)
foldr const 'a' [1..2]
to
(1 `const` (2 `const` 'a'))
Run Code Online (Sandbox Code Playgroud)
并且它的工作没有编译器错误
那么有什么问题呢?为什么第一个不工作,它的重写工作?
但我看到重写的形式const
有两种形式
Int -> Int -> Int
and
Int -> Char -> Int
Run Code Online (Sandbox Code Playgroud)
也许这是它的BCS所以我固定的类型,const
像这样
cont :: Int -> Int -> Int
cont = const
Run Code Online (Sandbox Code Playgroud)
现在当我说使用它时
(1 `cont` (2 `cont` 'a'))
Couldn't match expected type `Int' with actual type `Char'
Run Code Online (Sandbox Code Playgroud)
好像当我们使用多态函数时 Haskell 修复了它的类型,我们不能以其他形式使用它
也许它应该是列表折叠描述应该是这样的
folds like Text Rewriter,用函数替换cons(:),修复函数类型,用Accumulator替换空列表
请分享您对此的看法。
不仅 Haskell,其他类型语言也有相同的行为?
或者我完全错了?
在表达式中
(1 `const` (2 `const` 'a'))
---A--- ---B---
Run Code Online (Sandbox Code Playgroud)
我们使用了const
两次多态函数。每次使用都会导致多态函数类型被实例化为进行所有类型检查所需的任何类型。
一般类型const
为:
const :: a -> b -> a
Run Code Online (Sandbox Code Playgroud)
让我们假设数字文字具有类型Int
以保持解释简单。当我们写2 `const` 'a'
(--B--
上面的点)时,Haskell 理解a
上面的类型变量必须是Int
,而b
必须是Char
,所以这里我们使用
const :: Int -> Char -> Int
Run Code Online (Sandbox Code Playgroud)
因此, 的结果2 `const` 'a'
是 类型Int
。
知道了这一点,我们现在可以意识到上面const
使用的 at 点--A--
只有在我们选择类型变量a
和b
as 时才能进行类型检查Int
。所以,我们正在使用
const :: Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)
这是可能的,因为类型系统允许在使用函数的每个点都有不同的多态类型实例化。
注意到表达式可能会很有趣
(\c -> 1 `c` (2 `c` 'a')) const
Run Code Online (Sandbox Code Playgroud)
是一种简化(技术上:beta-reduces)原始表达式的表达式,但不可输入。这里,const
只使用了一次,所以它的类型只能实例化一次,但是没有一种类型实例化可以同时用于这两个c
点。这是类型推断引擎的一个已知限制,在执行 Hindley-Milner 推断的所有函数式语言之间共享。
您的使用foldr const ....
共享相同的问题。
起初看到我们可能有两个表达式可能会令人困惑,一个简化为另一个,但只有一个是可键入的。然而,这是生活中的事实。理论上,Haskell 满足以下“主题归约”性质:
e1
输入e1
了表达式e2
,并简化为表达式,则e2
输入表达式但是,Haskell(与大多数语言一样)无法满足以下“主题扩展”属性:
e2
输入e1
了表达式e2
,并简化为表达式,则e1
输入表达式因此,尽管这是不可能的是一个类型表达式简化为一个不适类型之一,它是可能的是一个不适输入表达式简化为一个类型之一。一个例子就是你找到的那个。一个更简单的是(\x -> True) ("ill-typed" "term")
类型错误的(它使用字符串作为函数)但简化为True
类型良好的。
我认为,它更简单,并且函数 const 不符合foldr 期望的签名:
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude> :t const
const :: a -> b -> a
Run Code Online (Sandbox Code Playgroud)
因此,haskell 尝试对a
和进行泛化b
(为了找出答案,它们都有足够的类型类集),最后发现这1
是一个数字,但 'c' 没有实现这个类型类。