这些 Haskell 类型是怎么回事?

Posted

技术标签:

【中文标题】这些 Haskell 类型是怎么回事?【英文标题】:What’s going on with these Haskell types? 【发布时间】:2022-01-23 02:50:45 【问题描述】:

为什么这个函数需要一个整数列表?

Prelude> :t \xs->[(map $ uncurry(*)) (zip xs [1..n]) | n<-[1..(length xs)]]
\xs->[(map $ uncurry(*)) (zip xs [1..n]) | n<-[1..(length xs)]]
  :: [Int] -> [[Int]]

当我将length xs 替换为固定值时,类型会发生变化并且不再那么严格:

Prelude> :t \xs->[(map $ uncurry(*)) (zip xs [1..n]) | n<-[1..100]]
\xs->[(map $ uncurry(*)) (zip xs [1..n]) | n<-[1..100]]
  :: (Num b, Enum b) => [b] -> [[b]]

我的编译器是

$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 8.8.4

【问题讨论】:

【参考方案1】:

length 具有Foldable t =&gt; t a -&gt; Int 类型,这意味着length xs 是一个Int 值。这使得[1..(length xs)] 的类型为[Int] 等。

另一方面,

100 不是 Int 文字,而是Num a =&gt; a 类型的多态文字。这使得[1..100] 具有Num a =&gt; [a] 等类型。

也就是说,length 是唯一在最终类型中强制使用像 Int 这样的具体类型的东西。将其替换为更通用的100,最终类型也更通用。

【讨论】:

所以,如果我理解的话,这归结为 (length [1,2,3]) * 4.5 在 Haskell 中是不可能的? 谢谢! fromIntegral 看起来很有用。 (*) 的类型为 Num a =&gt; a -&gt; a -&gt; a。两个操作数必须具有相同的类型,所以不,length [1,2,3] * 4.5 不进行类型检查。 "两个操作数必须具有相同的类型" 好的,这就是我必须学习的重点。 请注意Data.List 提供genericLength :: Num i =&gt; [a] -&gt; i,它使用您请求的任何Num 实例来提供长度。

以上是关于这些 Haskell 类型是怎么回事?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Haskell 中有“数据”和“新类型”? [复制]

Rust闭包和Haskell lambda有什么区别? [关闭]

函数的概念lambda 演算与 Haskell 语言——洪峰老师讲创客道(三十三)

Haskell 类型安全的空间使用

为啥我的 Haskell 函数参数必须是 Bool 类型?

对 Haskell 类型推断感到困惑