为什么Haskell在where子句内定义带守卫的次级函数会报|解析错误
问题复现场景
前期编写的两段代码可正常编译运行:
- 带空列表兜底的安全索引辅助函数
mI:
import Data.List import Data.Maybe mI l n | l == [] = Nothing | n == 0 = Just h | otherwise = mI t (n-1) where h = head l t = tail l
- 从
Maybe值中提取实际索引结果的myIndex函数:
myIndex l n | m == Nothing = error "No list." | otherwise = fromJust m where m = mI l n
当尝试将mI的实现直接内联到myIndex'的where子句中、省去顶层的独立mI定义时,触发编译错误:
触发错误的代码:
myIndex' l n | m == Nothing = error "No list." | otherwise = fromJust m where m = mI l n | l == [] = Nothing | n == 0 = Just h | otherwise = mI t (n-1) where h = head l t = tail l
编译输出的报错信息:
error: parse error on input `|'
错误核心原因
这里的解析错误不是因为Haskell不允许在where块内定义次级辅助函数,本质是写法违反了Haskell的绑定语法规则:
where子句内的所有绑定是平级的独立项,每个绑定的等号右侧是一个完整的表达式。你当前的写法,是把mI函数的守卫分支(也就是带|的多分支定义)直接拼接在m = mI l n这个变量绑定的等号后面。- 对解析器来说,
|是函数定义阶段的守卫标记,只能出现在独立函数定义的参数列表后面,不能出现在普通变量绑定的表达式中间。当解析器在m = mI l n后面遇到第一个|时,会误以为你要回到myIndex'函数的主体部分补充新的守卫分支,但你当前的代码已经处于where块的缩进层级内,语法上下文完全不匹配,因此直接抛出解析错误。
符合语法规则的嵌套写法
嵌套定义mI辅助函数的需求是完全合法的,只需要把辅助函数作为where块内的独立绑定项,和其他变量绑定保持平级即可,示例写法:
myIndex' l n | m == Nothing = error "No list." | otherwise = fromJust m where -- 作为where块的独立绑定定义,不嵌套在其他绑定的右侧 mI [] _ = Nothing mI l 0 = Just (head l) mI (_:t) n = mI t (n-1) m = mI l n
这种写法不需要在顶层单独定义mI,所有辅助逻辑都封装在myIndex'的作用域内,可正常编译运行。
内容的提问来源于stack exchange,提问作者147pm
相关产品推荐
相关产品推荐

