变量范围

问题描述:

在通过溶液至8皇后问题的工作,一个人使用下面的代码行:变量范围

sameDiag try qs = any (\(colDist,q) -> abs (try - q) == colDist) $ zip [1..] qs 

try是一个的项目; qs是相同项目的列表。

  1. 有人能解释lambda函数colDistq如何获取绑定到什么?

  2. 在lambda函数主体中使用tryq如何找到他们的方式进入相同的范围?

  3. 这是一个Haskell成语,这个设计方法有什么问题可以帮助解决?

+2

只是好奇:你想了解某人的作业吗? –

功能anyhigher-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,而不是目前的单态之一)

- 那么如何pairf pair = ... GET绑定到一个值?好吧,简单:它只是一个功能;无论谁调用它,都必须传递一个值为pair的论点。 - 当调用any并将第一个参数设置为f时,它是调用功能any谁正在调用f,并将xs列表中的单个元素作为参数pair的值传入。

并且,由于xs的内容是成对的列表,因此f期望它是这样的,将从该列表中的单个对传递到f是可以的。


编辑:any进一步的解释,以解决提问者的评论:

这是一个公平的合成?这种设计更高阶函数的方法允许调用代码改变f的行为,并调用带有列表的高阶函数,在列表中的每个元素被调用f之前需要额外的处理。封装列表处理(在这种情况下用zip)似乎是正确的做法,但这种额外处理的意图在上面的原始单行程中真正清楚了吗?

真的没有额外处理通过any进行调用f之前。除了简单地遍历传入的列表xs:在迭代期间在元素上调用f并且立即中断迭代并且第一次返回Truef对于任何列表元素返回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] 

- 请参阅您有时可以编写几乎与高阶函数看起来像英文的代码?

+0

不错,清晰的解释。当我读到“很好,很简单”的时候,我会同意,因为你如何制定逻辑。谢谢。 –

+0

这是一个公平的综合?这种设计更高阶函数的方法允许调用代码改变f的行为,并调用带有列表的高阶函数,在列表中的每个元素被调用f之前需要额外的处理。 封装列表处理(在这种情况下,带拉链),似乎做正确的事情,但是这是额外的处理的意图在原有上面的一行真的清楚吗? –

+0

什么额外的处理? 'zip'一如既往的处理,其结果被传递给'any'。而'any'不做任何额外的处理 - 它只是做了非常简单的簿记:第一次'f'返回'True',它也返回'True'并且停止分析列表的其余部分。我会编辑答案,并更详细地解释“any”的机制。 –

zip :: [a] -> [b] -> [(a,b)]需要两个列表并将它们连接成对,在结尾删除任何剩余的。

any :: (a -> Bool) -> [a] -> Bool取一个函数和一个a s的列表,然后返回True如果任何值返回true或不是。

所以colDistq是在由zip [1..] qs所作的列表中对第一和第二元件,并且当它们被any施加到一对它们所结合。

q只绑定在lambda函数的主体内 - 这与lambda微积分相同。由于try在函数定义之前被绑定,所以它仍然可以在这个内部范围内使用。如果您想到lambda微积分,术语\x.\y.x+y是合理的,尽管xy被绑定在不同的时间。

至于设计方法,这种方法比尝试手动迭代或递归列表要干净得多。对我来说,它的意图似乎很清楚(关于它来自更大的代码库)。

+1

这太好了。 q的解释特别有用。谢谢! –