瑞典人怎么会非常瑞典问候?

问题描述 投票:7回答:3

考虑以下Haskell定义,取自this excellent Haskell video on YouTube

import Data.List
greeting = "Hello"
swedish = intersperse 'f'
very f x = f (f (f x))

如果我们将它们加载到GHCi中,我们会看到以下结果:

ghci> swedish greeting
"Hfeflflfo"
ghci> very swedish greeting
"Hfffffffeffffffflffffffflfffffffo"
ghci> very very swedish greeting
"Hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fffffffffffffffffffffffffffff... (536,870,913 chars total)

前两个输出我完全理解。 swedish greeting散布着fs,而very swedish greeting只是一个swedish (swedish (swedish greeting)),三重穿插出来。

但究竟在第三个输入线上发生了什么?我对Haskell语法的理解(相当不完整)表明,以空格分隔的表达式序列被解释为函数调用,其中第一个表达式是函数,其余表达式是参数。在那种情况下,当它被定义为接受两个参数时,如何用三个参数(veryveryswedish)调用最外面的greeting

如果它有帮助,看起来very very swedish greeting相当于swedish $ swedish $ swedish $ swedish $ ... (27 layers of swedish) ... $ swedish $ swedish greeting

haskell composition higher-order-functions
3个回答
11
投票

你说:

我对Haskell语法的理解(相当不完整)表明,以空格分隔的表达式序列被解释为函数调用,其中第一个表达式是函数,其余表达式是参数。

你是对的,这不完全理解实际发生的事情。从你的例子:

very very swedish greeting

这与:

((very very) swedish) greeting

这是因为函数应用程序是左关联的。此外,Haskell中的每个函数都接受一个输入并返回一个结果。您认为接受多个输入的函数实际上是接受单个输入并返回函数作为结果的函数。

这也解释了为什么箭头( - >)分隔函数输入并导致函数类型。考虑++的类型:

(++) :: [a] -> [a] -> [a]

这与:

(++) :: [a] -> ([a] -> [a])

您可能会认为++运算符采用两个列表并返回一个列表,但实际上它是一个输入(列表)的函数,它返回一个返回列表的输入(另一个列表)的函数。

总而言之,你可以希望看到very very本身就是一个有效的表达式(并且碰巧与very具有相同的类型)。

very very x

相当于:

very (very (very x))

3
投票

函数应用程序是左关联的,所以

very very swedish greeting

相当于

((very very) swedish) greeting

qazxsw poi有类型qazxsw poi。 qazxsw poi可以作为very的第一个参数传递

(t -> t) -> t -> t

very也是一个函数,它有very类型。由于very :: (t -> t ) -> t -> t very :: (t -> t) -> (t -> t) very very :: (t -> t) -> (t -> t) very very类型,它可以传递给(t -> t) -> t -> t。结果函数的类型为swedish

String -> String

类型为very very的函数可以应用于String -> String

((very very) swedish) :: String -> String

1
投票

Daniel Pratt的回答解释了句法层面上发生的事情。但为什么String -> String导致greeting :: String被应用27次而不是其他数字呢?为了解决这个问题,让我们创建一个比(((very very) swedish) greeting) :: String 更通用的函数,它应用函数(very very)次:

swedish

让我们停止使用very,而是使用n,这样就可以更轻松地计算函数的应用次数:

-- Takes number of times to apply `n` and a function `f`, and returns a
-- function that applies `f` `n` times.
appn n f
  | n == 1    = f
  | otherwise = f . (appn (n - 1) f)

-- If necessary, you could define very = (appn 3)
very = (appn 3)

你现在可能会看到这种模式。 swedish产生相当于(+1)。但为什么?考虑一下Vandelay Industries> (appn 3) (appn 3) (+1) 0 27 Vandelay Industries> (appn 2) (appn 3) (+1) 0 9 Vandelay Industries> (appn 2) (appn 4) (+1) 0 16 Vandelay Industries> (appn 4) (appn 10) (+1) 0 10000 Vandelay Industries> (appn 2) (appn 2) (appn 2) (+1) 0 16 (appn x) (appn y)意味着appn $ y ^ x(appn 2) (appn 3)。把它通过(appn 3)和每个f (f (f x))实际应用3次:f . f . f或总共9次。

© www.soinside.com 2019 - 2024. All rights reserved.