haskell教程之间的区别

时间:2014-12-04 17:42:30

标签: haskell ghci

我最近开始在讲座中学习Haskell,但是当我试图找到进一步解释以了解它如何在线工作时,我发现代码看起来完全不同。注意:我之前只学过C,并习惯了大多数类似格式的代码,看起来类似。

例如,我讲座中数字阶乘的函数如下所示:

{-**********-}

fac :: Int -> Int
fac n
    | n==0  = 1
    | n>0   = n * fac (n-1)

{-**********-}

但是当我在网上看起来它看起来完全不同,而且更加简单。例如:

factorial 1 = 1
factorial k = k * factorial (k-1)

任何人都可以解释为什么我所教的代码更有效,特别是在它所说的

fac:: Int->Int 

为什么这很重要?

4 个答案:

答案 0 :(得分:3)

你要问的是函数类型签名,就像C中的函数原型声明一样。具体的行说明函数fac正在取Int参数并返回{{1}结果。这在Haskell中并不总是必要的,因为它可以推断出使用函数的上下文类型。其他差异只是处理案例的不同方法。第一个叫做 guards ,第二个是模式匹配
一般来说,我强烈推荐这个资源,以便轻松有趣的Haskell学习:Learn You a Haskell for Great Good!

更新:
只是简单解释为什么在这种特定情况下类型签名是必不可少的。假设你有两个不同的功能,一个带签名,另一个没有:

Int

然后,如果我们尝试执行类似factorial1 :: Int -> Int factorial1 n | n==0 = 1 | n>0 = n * factorial1 (n-1) factorial2 1 = 1 factorial2 k = k * factorial2 (k-1) 的操作,haskell将抛出错误,因为它知道factorial1 3.5不是Int。但是对于3.5 haskell只知道我们正在使用数字,factorial2就好了。但是对于输入3.5,它将以无限循环结束,因为它永远不会达到边界条件(k = 1)。这就是有时候签名必不可少的原因。有时相反,你希望你的函数对于不同的类型是通用的,但在这种情况下你仍然应该有一些签名定义一些更通用的类型约束(haskell有这样的工具)。

答案 1 :(得分:0)

fac:: Int->Int 

是函数的类型签名。它接受Int类型的参数并返回Int。

这些对文档很有用。

Haskell能够自行推断类型,请参阅以下链接:https://www.haskell.org/haskellwiki/Type_inference

  

"类型推断是类型系统的一个特征,这意味着具体类型是由类型系统推导出来的,而且很明显"

这意味着我们不必提供类型签名。

第一个例子使用一种叫做守卫的东西。有关警卫的更多信息,请参阅此链接: http://learnyouahaskell.com/syntax-in-functions#guards-guards

第二个使用模式匹配。 (参见上面的链接,向上滚动到模式匹配)

在这种情况下,这只是解决同一问题的两种不同方式。

答案 2 :(得分:0)

这两种方法都没有任何好处或坏处。他们只是一个偏好的问题。话虽这么说,两个函数都应该有类型签名Int -> Int(即使它们在两种情况下都是可选的),因为它提高了可读性,如果你做错了,类型检查器会抱怨。因此,这两个代码实际上是相同的:您在第一个版本中使用了防护,在第二个版本中使用了模式匹配。

此外,this question为类型签名对两个函数都有好处提供了一些好处。

答案 3 :(得分:0)

如果您想了解有关这些类型签名的更多信息,在GHCI或您自己的程序中使用:t工具非常有用。如果您对为什么会遇到类型与预期类型不匹配的错误感到好奇,您可以随时查看函数的类型。所以在GHCI中输入:t take或:t repeat:t复制......你明白了。当你进入列表和元组时帮助很多......