Haskell:将函数应用于所有参数组合

Cza*_*rek 6 haskell

我在Haskell的一些代码下面发帖.请将代码作为一个例子,我将使用它来解释我想知道的内容.

try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]]
try (a:as) (b:bs) (c:cs)  | ((checkIfCorrect a b c) == True) =  a:b:[c]
                          | otherwise = try as bs cs 

checkIfCorrect :: [Char] -> [Char] -> [Char] -> Bool
checkIfCorrect a b c = True
Run Code Online (Sandbox Code Playgroud)

最终,只checkIfCorrect返回True一个参数组合.checkIfCorrect功能很长,所以我决定在这里发帖.在上面的示例中,函数checkIfCorrect(通过函数try)应用于:首先[Char]在第一个列表上,第一个[Char]在第二个列表上,第[Char]一个在第三个列表中.如果未满足第一个保护方程,则将函数checkIfCorrect应用于:第[Char]一个列表中的第二个......依此类推.我想达到的目的是将函数checkIfCorrect(通过函数try)应用于[Char]所有列表([[Char]])的所有s 组合.我的意思是以下(例如):第[Char]一个列表上的第三[Char]个,第二个列表上的第八 个,[Char]第三个列表上的第11 个,依此类推.每个人都有.我怎么能轻易达到这个目标?

Ben*_*son 11

我只是想向您展示编写@ WillemVanOnsem代码的另一种方法.我猜你是Haskell的初学者,所以希望这个答案会让你对一个丰富而美丽的想法有一点了解,你很快就会在学习语言的过程中学到很多东西.所以,如果你不理解这段代码的所有内容,请不要太担心; 我只想尝试给你一个味道!

列表理解总是可以使用list monad重新表达:

import Control.Monad (guard)

try as bs cs = head $ do
    a <- as
    b <- bs
    c <- cs
    guard $ checkIfCorrect a b c
    return [a,b,c]
Run Code Online (Sandbox Code Playgroud)

我使用do符号作为嵌套循环的特殊符号:对于每个ain as,bin in bs和each cin cs,我们产生[a,b,c]if checkIfCorrect返回True.列表推导的翻译很简单:列表推导的"枚举"部分变成"绑定"使用<-,"过滤"变成调用guard,"屈服"变成returns.

在像Python这样的命令式语言中,您可以像这样编写它:

def try(as, bs, cs):
    for a in as:
        for b in bs:
            for c in cs:
                if checkIfCorrect(a, b, c):
                    yield [a,b,c]
Run Code Online (Sandbox Code Playgroud)

就像西方新自由主义霸权下的政治一样,势在必行的代码逐渐向前发展.像这样的"楼梯"代码实际上在命令式编程中频繁出现(想想JS中的"回调地狱"),因此发明monad来帮助抵消这种趋势.事实证明它们非常有用,为它们发明了一种特殊的语法,即 - do注释.

  • 最后一段是可引用的.:) (5认同)

Wil*_*sem 5

是的,你可以通过列表理解使它看起来更优雅:

try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]]
try as bs cs = head [ [a,b,c] | a <- as, b <- bs, c <- cs, checkIfCorrect a b c ]
--                    \__ __/   \__________ ____________/  \__________ _______/
--                       v                 v                          v
--                     yield           enumeration                 filter
Run Code Online (Sandbox Code Playgroud)

代码的工作原理如下:列表推导的右侧部分由" 枚举 "部分组成(由注释部分表示).因为我们写a <- as, b <- bs, c <- cs它意味着a将取任何值as,并且对于每个这样的值a,b将取任何值bs,等等.这意味着将发出每个可能的组合.

接下来是" 过滤器 "阶段:有一个谓词checkIfCorrect a b c将被调用,只有当该谓词返回时True,结果才会被"屈服".

在左侧,我们看到" 收益率 ".它描述了在过滤器成功的情况下要添加到列表中的内容(基于枚举).如果发生这种情况,我们会添加[a,b,c]到该列表 如果有多个此类配置成功,我们最终可能会得到一个包含多个解决方案的列表.但请注意,列表理解是懒惰的:所以只要你不要求至少一个这样的元素,它就不会生成第一个元素,也不会生成第二个元素,等等.

现在我们也需要head(在列表理解之前).head :: [a] -> a返回列表的第一个元素.因此try将返回满足条件的第一个元素.