变量范围
在通过溶液至8皇后问题的工作,一个人使用下面的代码行:变量范围
sameDiag try qs = any (\(colDist,q) -> abs (try - q) == colDist) $ zip [1..] qs
try
是一个的项目; qs
是相同项目的列表。
有人能解释lambda函数
colDist
和q
如何获取绑定到什么?在lambda函数主体中使用
try
和q
如何找到他们的方式进入相同的范围?这是一个Haskell成语,这个设计方法有什么问题可以帮助解决?
功能any
是higher-order function在于需要两个参数:
- 的第一参数是
a -> Bool
类型的,即,从a
一个函数来Bool
- 的第二参数是类型
[a]
,即类型为a
的项目列表;
即第一参数是一个函数,它从作为第二参数传递的列表中的任何元件,并返回基于该元件上的Bool
。(当然也可以采取a
型,不只是在该列表中的人的任何值,但它是很明显肯定any
不会从列表a
一些任意值,但那些被调用它。)
然后,您可以简化做轻微的重构想着原来的片段:
sameDiag :: Int -> [Int] -> Bool
sameDiag try qs = any f xs
where
xs = zip [1..] qs
f = (\(colDist, q) -> abs (try - q) == colDist)
可转化成
sameDiag :: Int -> [Int] -> Bool
sameDiag try qs = any f xs
where
xs = zip [1..] qs
f (colDist, q) = abs (try - q) == colDist)
这反过来又可以转化为
sameDiag :: Int -> [Int] -> Bool
sameDiag try qs = any f xs
where
xs = zip [1..] qs
f pair = abs (try - q) == colDist) where (colDist, q) = pair
(注意,sameDiag
也可以有一个更普遍的类型Integral a => a -> [a] -> Bool
,而不是目前的单态之一)
- 那么如何pair
在f pair = ...
GET绑定到一个值?好吧,简单:它只是一个功能;无论谁调用它,都必须传递一个值为pair
的论点。 - 当调用any
并将第一个参数设置为f
时,它是调用功能any
谁正在调用f
,并将xs
列表中的单个元素作为参数pair
的值传入。
并且,由于xs
的内容是成对的列表,因此f
期望它是这样的,将从该列表中的单个对传递到f
是可以的。
编辑:的any
进一步的解释,以解决提问者的评论:
这是一个公平的合成?这种设计更高阶函数的方法允许调用代码改变f的行为,并调用带有列表的高阶函数,在列表中的每个元素被调用f之前需要额外的处理。封装列表处理(在这种情况下用zip)似乎是正确的做法,但这种额外处理的意图在上面的原始单行程中真正清楚了吗?
真的没有额外处理通过any
进行调用f
之前。除了简单地遍历传入的列表xs
:在迭代期间在元素上调用f
并且立即中断迭代并且第一次返回True
f
对于任何列表元素返回True
之外,还有非常简约的簿记。
大多数any
的行为是“隐性”,虽然在它是由Haskell的惰性计算的照顾,基本语言语义以及现有的功能,这any
如下组成的(嗯,至少我的版本的话, any'
- 我还没有看看内置Prelude
版本的any
,但我相信它没有太大的不同,只是可能更加优化)。
事实上,any
很简单,它几乎微不足道上一个GHCI提示一个班轮重新实现它:
Prelude> let any' f xs = or (map f xs)
让我们看看现在是什么GHC计算作为其类型:
Prelude> :t any'
any' :: (a -> Bool) -> [a] -> Bool
- 与内置的any
相同。因此,让我们试试一下:
Prelude> any' odd [1, 2, 3] -- any odd values in the list?
True
Prelude> any' even [1, 3] -- any even ones?
False
Prelude> let adult = (>=18)
Prelude> any' adult [17, 17, 16, 15, 17, 18]
- 请参阅您有时可以编写几乎与高阶函数看起来像英文的代码?
不错,清晰的解释。当我读到“很好,很简单”的时候,我会同意,因为你如何制定逻辑。谢谢。 –
这是一个公平的综合?这种设计更高阶函数的方法允许调用代码改变f的行为,并调用带有列表的高阶函数,在列表中的每个元素被调用f之前需要额外的处理。 封装列表处理(在这种情况下,带拉链),似乎做正确的事情,但是这是额外的处理的意图在原有上面的一行真的清楚吗? –
什么额外的处理? 'zip'一如既往的处理,其结果被传递给'any'。而'any'不做任何额外的处理 - 它只是做了非常简单的簿记:第一次'f'返回'True',它也返回'True'并且停止分析列表的其余部分。我会编辑答案,并更详细地解释“any”的机制。 –
zip :: [a] -> [b] -> [(a,b)]
需要两个列表并将它们连接成对,在结尾删除任何剩余的。
any :: (a -> Bool) -> [a] -> Bool
取一个函数和一个a
s的列表,然后返回True
如果任何值返回true或不是。
所以colDist
和q
是在由zip [1..] qs
所作的列表中对第一和第二元件,并且当它们被any
施加到一对它们所结合。
q
只绑定在lambda函数的主体内 - 这与lambda微积分相同。由于try
在函数定义之前被绑定,所以它仍然可以在这个内部范围内使用。如果您想到lambda微积分,术语\x.\y.x+y
是合理的,尽管x
和y
被绑定在不同的时间。
至于设计方法,这种方法比尝试手动迭代或递归列表要干净得多。对我来说,它的意图似乎很清楚(关于它来自更大的代码库)。
这太好了。 q的解释特别有用。谢谢! –
只是好奇:你想了解某人的作业吗? –