Haskell偏函数组合语法报错:无法匹配Bool与Char->Bool类型
错误原因
- Haskell的
||运算符类型为Bool -> Bool -> Bool,仅能连接两个布尔值,无法直接拼接两个Char -> Bool类型的判断函数。你在守卫中写的isAsciiAlpha || C.isSpace、以及isAsciiAlpha定义里的C.isAsciiLower || C.isAsciiUpper,都是试图直接用||拼接函数,编译器在此处期望得到Bool类型操作数,实际拿到的是Char -> Bool类型的函数,因此抛出类型不匹配错误。 - 函数组合的写法也存在逻辑错误:
not的类型是Bool -> Bool,你写的(判断函数) . not无法实现“对判断结果取反”的效果,函数组合要求右侧函数的返回值类型和左侧函数的入参类型匹配,这种写法本身类型就不成立。
正确写法
首先修正基础判断函数的定义,给判断传入明确的字符参数:
isAsciiAlpha :: Char -> Bool isAsciiAlpha c = C.isAsciiLower c || C.isAsciiUpper c
之后修正守卫的判断逻辑,用lambda显式声明对单个字符的判断规则:当存在任意字符既不是ASCII字母、也不是空格时,直接返回False:
isValid :: String -> Bool isValid n | any (\c -> not (isAsciiAlpha c || C.isSpace c)) n = False | otherwise = ys > 1 && sum xxs `mod` 10 == 0 where -- 注意:你当前这里筛选isAsciiAlpha和后续digitToInt的逻辑存在矛盾 -- Luhn校验处理的是数字字符,这里大概率应该写C.isDigit而不是isAsciiAlpha xs = reverse [c | c <- n, isAsciiAlpha c] ys = length xs zs = zip xs (cycle [1,2]) xxs = [convert x y | (x,y) <- zs]
如果偏好无点(point-free)风格,也可以导入Control.Applicative模块,用liftA2 (||)来组合两个同类型的谓词函数,写法如下:
import Control.Applicative (liftA2) -- 组合两个Char->Bool的判断函数 isValidChar :: Char -> Bool isValidChar = liftA2 (||) isAsciiAlpha C.isSpace -- 守卫处可改写为 | any (not . isValidChar) n = False
注:你当前代码中筛选待处理字符时用了
isAsciiAlpha判断,但后续convert调用C.digitToInt处理字符,传入字母时会得到非预期的十六进制转换结果甚至抛出错误,和Luhn校验处理数字串的需求不符,建议将筛选条件改为判断数字字符C.isDigit。
内容的提问来源于stack exchange,提问作者Abhijit Sarkar
相关产品推荐
相关产品推荐

