Haskell列表推导括号用法及crosswordFind函数实现问题
问题解答
1. 为什么你写的方括号不能用来分隔代码
Haskell 中的[]是列表专用语法,作用只有构造列表,不存在「分隔代码段」的语法作用。
你把判断表达式包在[]里,相当于把布尔类型的判断结果转换成了单元素布尔列表,而&&运算符只能作用于布尔值,不能作用于列表,这种写法本身就会触发类型错误。同时你初始版本外层的[]会把整个if表达式返回的[String]结果作为列表的唯一元素,得到的是[[String]]类型,和你声明的函数返回值[String]不匹配,这也是你提到返回长度为1的列表的原因。
如果需要调整运算优先级,Haskell 仅支持用小括号()包裹表达式,不要混淆其他语言的中括号用法。
2. 用列表推导实现crosswordFind函数
crosswordFind :: Char -> Int -> Int -> [String] -> [String] crosswordFind letter pos len words = [ word | word <- words, length word == len, -- 匹配单词长度要求 pos >= 0, pos < length word, -- 下标越界防护,避免运行时报错 word !! pos == letter -- 匹配指定位置的字符 ]
你给出的测试用例crosswordFind 'k' 1 7 ["funky", "fabulous", "kite", "icky", "ukelele"]运行后会返回["ukelele"],符合预期。
3. 现有代码加粗部分的修正方案
你现有修改后的代码逻辑本身存在结构性问题:没有遍历words里的每个单词,直接对整个单词列表做判断,就算只替换加粗内容也无法正常运行,需要先调整整体逻辑,再修正你写反的条件参数。
你原代码的三个判断条件全部参数顺序错误,修正后的过滤逻辑如下:
crosswordFind :: Char -> Int -> Int -> [String] -> [String] crosswordFind letter pos len words = filter (\word -> length word == len && word !! pos == letter) words
如果非要保留你原来的if-else结构,需要把判断逻辑放到对每个单词的遍历中:
crosswordFind :: Char -> Int -> Int -> [String] -> [String] crosswordFind letter pos len words = concatMap (\word -> if length word == len && word !! pos == letter then [word] else []) words
你原来三处加粗内容对应的错误分别是:
- 第一个
words:不需要调用isAlpha做额外判断,且你应该取单个单词的指定位置字符,而非操作整个单词列表 - 第二个
words:你把下标和取值的参数写反了,正确逻辑是单词 !! 位置下标 == 目标字符,不是列表 !! 字符 == 位置下标 - 第三个
pos:对Int类型的pos求长度属于类型错误,正确逻辑是求单个单词的长度等于给定长度len
内容的提问来源于stack exchange,提问作者idontknowhowtocode
相关产品推荐
相关产品推荐

