在解决8皇后区问题的过程中,一个人使用了以下代码行:
sameDiag try qs = any (\(colDist,q) -> abs (try - q) == colDist) $ zip [1..] qs
try
是一个项目; qs
是相同项目的列表。
有人可以解释lambda函数中的colDist
和q
如何绑定到任何东西?
lambda函数体中使用的try
和q
如何进入同一范围?
在某种程度上,这是一个Haskell习语,这种设计方法有什么问题有助于解决?
答案 0 :(得分:0)
zip :: [a] -> [b] -> [(a,b)]
获取两个列表并将它们成对加入,最后删除剩余的列表。
any :: (a -> Bool) -> [a] -> Bool
接受一个函数和a
的列表,然后如果任何值返回true,则返回True
。
因此colDist
和q
是由zip [1..] qs
生成的列表中对的第一个和第二个元素,并且当它们应用于{{1 }}
any
仅绑定在lambda函数的主体内 - 这与lambda演算相同。由于q
之前已在函数定义中绑定,因此它仍可在此内部范围中使用。如果你想到lambda演算,那么术语try
是有道理的,尽管\x.\y.x+y
和x
在不同的时间被绑定。
至于设计方法,这种方法比尝试手动迭代或递归列表要简洁得多。它对我的意图似乎很清楚(关于它来自更大的代码库)。
答案 1 :(得分:0)
函数 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 = ...
如何绑定到某个值?好吧,简单:它只是一个功能;无论谁调用它都必须传递pair
参数的值。 - 在第一个参数设置为any
的情况下调用f
时,调用any
的函数f
的调用与列表中的各个元素{{} { 1}}作为参数xs
的值传入。
并且,由于pair
的内容是对的列表,因此可以将此列表中的单个对传递给xs
,因为f
期望它只是那个。 / p>
编辑:对f
的进一步解释,以解决提问者的评论:
这是一个公平的综合吗?这种设计高阶函数的方法允许调用代码改变f的行为方式并且在用于为列表中的每个元素调用f之前需要额外处理的列表调用高阶函数。封装列表处理(在这种情况下使用zip)似乎是正确的做法,但这个额外处理的目的是否真的在上面的原始单行中清楚了?
在调用any
之前,any
确实没有额外的处理。除了简单地遍历传入的列表f
之外,还有非常简约的簿记:在迭代期间对元素调用xs
,并立即打破迭代并在第一次返回f
True
为任何列表元素返回f
。
True
的大部分行为都是“隐含的”,但它由Haskell的懒惰评估,基本语言语义以及any
组成的现有函数来处理(嗯至少我的下面的版本,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]
- 看看你如何有时编写几乎看起来像英语的高阶函数的代码?