Haskell是否需要将所有入参转换为lambda?自定义map函数运行报错如何解决
问题解答
是否需要将所有输入转换为lambda形式
完全没有必要。Haskell的顶层函数参数声明本身就是lambda抽象的语法糖,比如f a b = ...和f = \a b -> ...的语义完全一致,你可以根据代码可读性的需求自由选择写法,不需要强行将所有参数都用lambda形式定义。
报错原因分析
你给出的map_定义为:
map_ xs = \f -> case xs of [] -> [] y:ys -> (f y):(map f ys)
这个定义的实际类型为[a] -> (a -> b) -> [b]:即map_第一个参数接收列表xs,返回一个接收函数f的高阶函数,需要先传列表、再传函数才能得到最终的映射结果。
而你的调用写法是map_ square [3,4],参数顺序完全反过来了,类型检查逻辑如下:
map_要求第一个参数为列表类型,你传入了函数square后,得到的返回值是一个期望接收函数参数的高阶函数(类型为a -> b)- 你紧接着给这个高阶函数传入了列表
[3,4],列表类型[c]和期望的函数类型a->b不匹配,因此抛出对应的类型错误。
此外你的代码还有一个隐性问题:递归调用时你写的是map f ys,调用的是标准库的map而非你自定义的map_,后续功能运行也会出现预期外的结果。
修复方法
有两种可选修复方案:
方案1:修改调用方式匹配现有定义
保持map_的现有实现逻辑不变,调整递归调用的函数名,同时修改参数顺序调用即可:
修改后的函数定义:
map_ xs = \f -> case xs of [] -> [] y:ys -> (f y):(map_ f ys)
调用写法改为:
map_ [3,4] square
方案2:修改函数定义匹配标准map的参数顺序
如果你希望和标准库map的用法(先传函数,后传列表)保持一致,调整函数的参数定义即可:
-- 普通参数写法 map_ f xs = case xs of [] -> [] y:ys -> (f y) : map_ f ys
如果你偏好lambda写法,也可以写成:
-- lambda形式写法 map_ = \f xs -> case xs of [] -> [] y:ys -> (f y) : map_ f ys
修改后直接用你原来的调用写法map_ square [3,4]即可正常运行。
内容的提问来源于stack exchange,提问作者blueMountain
相关产品推荐
相关产品推荐

