代码之家  ›  专栏  ›  技术社区  ›  pcoppi

尝试在Haskell和根据-Wall编写函数时,我需要一个匹配(\u:\ u:\ u)的模式。这个模式意味着什么,为什么我需要它?

  •  2
  • pcoppi  · 技术社区  · 6 年前

    所以我想自己尝试创建这个函数(将列表中的所有内容乘以3,然后返回一个新列表):

    list = [1,2,3,4,5,6,7,8,9,10]
    list2 = [3 * x | x <- list]
    

    我使用了防护装置(基本上,当x到达列表的边界时,它就会停止):

    tripleMultList :: [Int] -> Int -> [Int]
    tripleMultList lst x
       | null lst = []
       | length lst - 1 == x = (lst !! x * 3) : []
       | otherwise = (lst !! x * 3) : tripleMultList lst (x + 1)
    

    然后我决定尝试使用模式匹配:

    tripleMultList :: [Int] -> Int -> [Int]
    tripleMultList [] x = []
    tripleMultList [y] x | x == (length [y] - 1) = [y] !! x : []
    tripleMultList [y] x = [y] !! x : tripleMultList [y] (x + 1)
    

    但是每当我尝试运行这个函数时,我都会得到一个非穷举的模式匹配错误,所以我检查了ghci-Wall,它说我需要一个匹配到

    (_:_:_) _ 
    

    我想它的形式是

    tripleMultList (_:_:_) _ = something
    

    我知道

    (_:_:_)
    

    必须从列表中选择元素并将其与列表本身分离,尽管我不知道为什么这会应用于我的函数。我也不知道“\u0”是什么意思或作用,以及它如何应用于我的函数。

    所以我想我的问题是,这个模式意味着什么?为什么我需要它,当我的函数版本中有大致相同的东西,使用了一个保护,而这个保护工作得很好?

    2 回复  |  直到 6 年前
        1
  •  4
  •   Daniel Wagner    6 年前

    函数接受两个参数。GHCI告诉您,您尚未为遵循该模式的函数调用提供定义

    tripleMultList (_:_:_) _
    

    i、 e.当第一个参数与模式匹配时 _:_:_ 第二个参数与模式匹配 _ .模式 _ 匹配所有内容。模式 _:\u:_ 匹配列表,其中第一个元素是任意元素,第二个元素是任意元素,列表的其余部分是任意元素。换句话说, _:\u:_ 匹配至少两个元素的列表。

    查看您定义的案例:

    tripleMultList [] x = []
    tripleMultList [y] x | x == (length [y] - 1) = [y] !! x : []
    tripleMultList [y] x = [y] !! x : tripleMultList [y] (x + 1)
    

    这就是:

    • 第一个参数:空列表;第二个论点:什么都可以。
    • 第一个参数:具有单个元素的列表;第二个论点:任何东西;只有 x == (length [y] - 1) 是真的。
    • 第一个参数:具有单个元素的列表;第二个论点:任何东西;仅当不满足上述条件时。

    这就排除了第一个参数是至少包含两个元素的列表的情况。

    如果要在第一个定义中遵循分解,那么需要使用 y 在第二和第三个定义中,而不是 [y] .模式 Y (变量)匹配(正确类型的)任何内容并为其命名 Y .模式 【y】 匹配一个元素的任何列表,并为该元素指定名称 Y

        2
  •  0
  •   chepner    6 年前

    你几乎从不想使用 !! ,尤其是不用于迭代列表。记住列表的定义:

     data [] a = [] | a : [] a
    

    只有两种模式需要匹配:空列表( [] )和非空列表( x:y )。空列表的大小写正确:将空列表的每个元素相乘将生成另一个空列表。

    tripleMultList [] = []
    

    对于非空列表,您只需要稍微复杂一点的内容。您拥有第一个元素 x 其余元素为 y .你所需要做的就是乘法 十、 乘以3,并将其添加到 Y 到3:

    tripleMultList (x:y) = let x' = 3 * x
                               y' = tripleMultList y
                           in x' : y'
    

    注意,我们可以将其推广到 十、 :

    doSomething :: (a -> b) -> [a] -> [b]
    doSomething _ [] = []
    doSomething f (x:y) = let x' = f x
                              y' = doSomething f y
                          in x' : y'
    
    tripleMultList = doSomething (\x -> 3 * x)
    

    这种类型的操作非常常见 doSomething 已在Haskell中定义,但称为 map 相反