我正在学习haskell
我遇到了这个我无法理解的表达。
(flip const 1 . const flip 3 const 4) 5
最终结果是5,但我不知道它是如何评估的。
答案 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 y
仅id
为y
所有(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 1
和const 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) -> a
是fst
,没有别的,它对一对的第一个元素一无所知,所以它必须只返回它f :: (a, b) -> b
是snd
,出于同样的原因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
类型的函数,它的名称为undefined
。 undefined
是a
类型的值,也就是说,它居住在任何类型中。但那是另一个时间的主题。
练习:让我们继续玩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