这个haskell表达式是如何评估的

时间:2015-04-15 19:42:44

标签: haskell

我正在学习haskell我遇到了这个我无法理解的表达。

(flip const 1 . const flip 3 const 4) 5

最终结果是5,但我不知道它是如何评估的。

2 个答案:

答案 0 :(得分:16)

根据(.)

的定义
  flip const 1 $ ((const flip 3) const 4) 5

根据const

的定义
= flip const 1 $ flip const 4 5

根据flip

的定义
= flip const 1 $ const 5 4

根据const

的定义
= flip const 1 5

根据flip

的定义
= const 5 1

哪个是5

(作为一个小小的奖励洞察,您能否找出flip const yidy所有(id . id) 5的原因?这会将您的表达式降低为{{1}}。)

答案 1 :(得分:2)

每次在Haskell中看到一些“聪明”的函数调用时,请务必检查其类型,然后尝试在GHCi中使用它。

学习Haskell的唯一方法实际上是尝试一下,而你只是通过阅读StackOverflow答案或在线教程来做到这一点,你必须将表达式放入GHCi,失败,试图找出错误对于你自己,尝试在不同的地方替换不同的值以使错误消失,尝试将问题分成块并分别理解它们,等等。

如果不了解Haskell的类型系统(我承诺,并不难),就不可能对Haskell进行编码。如果您不了解例如“类型变量”的含义,请阅读Types and Typeclasses上的章节,并确保您努力尝试GHCi中的每个表达式。

您的原始表达是:

(flip const 1 . const flip 3 const 4) 5

(.)function composition,如果表达式为typechecks(即它没有引发编译时类型错误),则flip const 1const flip 3 const 4得到成为职能。

  

练习:现在打开GHCi并逐个输入以下内容并检查类型(:t GHCi命令是检查某个值的类型):

:t const
:t flip

首先,请记住关于Haskell类型系统的这一事实。如果在类型声明中存在类型变量,例如a,则该函数必须接受任何类型。如果存在由类型类限定的类型变量,例如f :: Num a => a -> a,那么函数必须接受任何类型,即类型类Num的实例(即任何数字)。你不能拥有一个返回a的函数,但是你在它的正文中返回String

其次,如果类型声明中有多个类型变量,则它们的类型始终相同。因此,如果您的某个函数的类型为f :: a -> a,并且您为其指定了Int,那么它必须返回Int。因为Haskell没有运行时类型检查,所以如果接受类型变量,则不能假设有关类型的任何内容。

这两个事实限制了一个函数可以做什么,如果它有某种类型。因此:

  • f :: a -> a总是返回参数;它不能推论这个论点,因为它不知道它的类型,它不能应用任何具有更多特定类型的函数,所以它必须只返回参数
  • f :: (a, b) -> afst,没有别的,它对一对的第一个元素一无所知,所以它必须只返回它
  • f :: (a, b) -> bsnd,出于同样的原因
  • f :: a -> b -> a接受2个参数并返回第一个
  • f :: b -> a -> a接受2个参数并返回第二个

这个限制是一件好事,因为仅仅通过查看类型你可以猜到很多关于这个功能。有些类型是不可能的,例如f :: a -> b,没有这种类型的函数(因为b会是什么样的?)。

请记住,类型声明中的->right-associative,因此:

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

都是等价的。因此,您可以将类型f :: a -> b -> c的函数视为接受2个参数并返回值,或者您可以将其视为接受1个参数并返回1参数的函数。

“等等”,你可能会说,“你说a -> b类型的函数是不可能的,那么f如何属于(a -> b -> c) -> b -> (a -> c)类型,也就是说,返回一个函数键入a -> c?“好吧,f实际上永远不会返回类型为a -> c的函数,因为您从未向其传递类型为a -> b -> c的函数。相反,您可以传递类型Int -> a -> [a]的函数并获取类型为a -> (Int -> [a])的函数。

然后你传递另一个值,让我们说String类型,给这个新函数。结果会得到类型为Int -> [String]的函数。现在Int -> [String]不是一个不可能的功能,是吗?

从技术上讲,您可以返回a -> b类型的函数,它的名称为undefinedundefineda类型的值,也就是说,它居住在任何类型中。但那是另一个时间的主题。

  

练习:让我们继续玩GHCi中的类型:

:t const
:t flip
:t const flip
:t flip const

您从这些类型中学到了什么?这些函数会忽略哪些参数?他们将返回哪些值(或函数)?

  

练习:如果您仍然不明白,我在哪里,请尝试按顺序将这些内容输入GHCi,以查看部分应用程序更改类型:

:t flip
:t flip const
:t flip const 1
:t const
:t const flip
:t const flip 3
:t const flip 3 const
:t const flip 3 const 4
:t id