嗨,我有一个关于简单的 haskell 定义的查询。我有一个定义,但我并不完全理解它。
该函数接受一个函数列表和一个项目,并返回一个通过应用该函数形成的列表。
applyAll = \fs -> \x -> map(\n -> n x) fs
有人可以解释 n 做什么以及为什么 fs 在 map 函数之外?
嗨,我有一个关于简单的 haskell 定义的查询。我有一个定义,但我并不完全理解它。
该函数接受一个函数列表和一个项目,并返回一个通过应用该函数形成的列表。
applyAll = \fs -> \x -> map(\n -> n x) fs
有人可以解释 n 做什么以及为什么 fs 在 map 函数之外?
间距会误导你。看起来像是map(\n -> n x)
一个函数调用,但这里的括号是用于分组,而不是函数调用。map
接受两个参数;完整的调用是map (\n -> n x) fs
,其中(\n -> n x)
第一个参数(一个 lambda 表达式)fs
是第二个。
lambda\n -> n x
是一个函数,它接受一个函数作为参数,并返回将该函数应用到x
. n
是这里的论点。的类型\n -> n x
是(a -> b) -> b
(其中a
的类型是x
)。如果您已经了解了 section,则 lambda 等效于 section ($ x)
。如果没有,请忽略最后一句话。
函数定义:
applyAll = \fs -> \x -> map(\n -> n x) fs
是相同的:
applyAll fs x = map(\n -> n x) fs
->
现在你可能会问,“如果它们只是我的函数的参数,那些s 在那里做了什么applyAll
。Haskell 没有多参数函数的概念。你所看到的函数的多个参数只是许多函数链接在一起,每个函数都有一个论点。在 的情况下,它只是两个链接在一起的函数:applyAll
(applyAll fs) -> x = map (\n -> n x) fs
applyAll fs
是一个链接到另一个参数的函数,该参数被标识为x
产生由 . 返回的值的列表map
。
我可以在 ghci 中尝试一下:
Prelude> :t applyAll
applyAll :: [t -> b] -> t -> [b]
Prelude> :t applyAll xs
<interactive>:1:10: Not in scope: `xs'
Prelude> let xs = [1..5]
-- hah, BOOM! I told you haskell's strongly typed...
Prelude> :t applyAll xs
<interactive>:1:10:
Couldn't match expected type `t0 -> b0' with actual type `Integer'
Expected type: [t0 -> b0]
Actual type: [Integer]
In the first argument of `applyAll', namely `xs'
In the expression: applyAll xs
Prelude> let xs = [(1 +), (2 +), (3 *), (4 /)]
Prelude> :t xs
xs :: [Double -> Double]
Prelude> :t applyAll xs
applyAll xs :: Double -> [Double]
Prelude> :t applyAll
applyAll :: [t -> b] -> t -> [b]
Prelude> :t applyAll xs 3
applyAll xs 3 :: [Double]
Prelude> applyAll xs 3
[4.0,5.0,9.0,1.3333333333333333]
是什么类型的map
?
map :: (a -> b) -> [a] -> [b]
这告诉我map
需要一个函数 - 让我们调用它f
和一个值列表来返回另一个值列表。该函数f
接受一个类型的值,a
返回另一个类型的值b
。所以map
继续应用f
到列表中的每个值[a]
以返回另一个填充了 type 值的列表b
。
在您的applyAll
中,功能f
是\n -> n x
。这是一个 lambda 表达式(您可以将其称为匿名函数),它采用由标识的值n
并应用于x
它。这对类型定义中标识的输入列表中的每个项目都进行,[a]
直到它用完以产生[b]
类型定义中标识的另一个列表。
这是一个简单的函数定义:
f x = 2*x + 1
这会创建一个新函数f
,它接受一个参数。您可以稍后像这样使用它:
main = print (f 3)
...这将打印 7。有时,定义一个函数而不给它一个名字是很方便的。语法是\{- argument -} -> {- function body -}
; 例如,我们可以通过f
这种方式执行上述的匿名版本:
main = print ((\x -> 2*x + 1) 3)
现在,您的定义applyAll
只是这样做了几次。where
如果需要,我们可以在子句中明确命名所有内容:
applyAll = outerMost where
outerMost fs = mapApply where
mapApply x = map applyToX fs where
applyToX n = n x
......虽然我认为你会同意额外的冗长不会让事情变得更清楚!远离匿名函数的更自然(但不那么机械)的转换如下所示:
applyAll fs x = map applyToX fs where
applyToX n = n x
现在希望这几乎可以像英语一样读起来:要将所有函数fs
应用于单个值x
,我们将“将单个函数(我们暂时命名n
)应用于值的函数”映射到x
所有函数的列表上。