Home Articles

Haskell错误:非详尽的模式

Asked
Viewed 401 times
1

我正在尝试编写一个函数来计算句子中的单词 .

cwords :: String -> Int
cwords "" = 0
cwords (a:b:c)
    |isAlpha a && (isAlpha b == False) = 1 + cwords (b:c) 
    |otherwise = cwords (b:c)

每当我输入一个句子时,我都会收到一条错误,上面写着“函数cwords中的非详尽模式” . 空字符串工作正常 . (我对Haskell很新)

1 Answer

  • 5

    问题是您定义了两个子句:

    • 一个空列表
    cwords "" = 0
    
    • 和列表包含至少两个元素的一个:
    cwords (a:b:c) = ...
    

    所以Haskell说,如果字符串只包含一个字符,它就不知道该怎么做,因为没有子句指定在这种情况下要做什么 .

    由于你计算单词,如果我们获得最后一个字符,我们应该把它算作一个单词(假设它是一个字母字符) . 所以代码应该是:

    cwords :: String -> Int
    cwords "" = 0
    cwords (a:b:c)
        |isAlpha a && (isAlpha b == False) = 1 + cwords (b:c) 
        |otherwise = cwords (b:c)
    

    至:

    cwords :: String -> Int
    cwords "" = 0
    cwords [_] | isAlpha a = 1
    cwords (a:b:c)
        |isAlpha a && (isAlpha b == False) = 1 + cwords (b:c)
        | otherwise = cwords (b:c)
    

    话虽这么说,我们仍然可以改进代码:

    • 我们可以使用 not (isAlpha b) 而不是 isAlpha b == False ;

    • 如果我们知道 b 不是 isAlpha ,那么我们不必在 (b:c) 上执行递归,但可以直接在 c 上执行递归;和

    • 我们可以将 otherwise case重写为处理包含至少一个元素的列表的子句 .

    导致:

    cwords :: String -> Int
    cwords "" = 0
    cwords [a] | isAlpha a = 1
    cwords (a:b:c) |isAlpha a && not (isAlpha b) = 1 + cwords c
    cwords (_:b) = cwords b
    

Related