我正在尝试实现一个foreach态射,以便测试我对态射定义和模式匹配的理解......显然我完全错过了这两点。
你可以纠正我吗?我希望态射foreach
将a
和态射f
列表作为参数,并返回应用r
的所有结果f
的列表所有a
个元素。
foreach :: [a] → f → [r]
foreach [] f = []
foreach x:[] f = (f x):[]
foreach []:x f = []:(f x)
foreach (x:xs) f = (f x) : (foreach (xs f))
编译时,我有src\Main.hs:23:0: Parse error in pattern
答案 0 :(得分:13)
问题是语法,在这一行:
foreach x:[] f = (f x):[]
模式中的构造函数应用程序通常需要括起来。这可行:
foreach (x:[]) f = (f x):[]
顺便提一下......函数应用程序是最高优先级,所以另一方面你不需要在右侧括号:
foreach (x:[]) f = f x:[]
以上适用于任何中缀构造函数,但作为最后一点,特别是对于列表,有一种特殊的语法:
foreach [x] f = [f x]
您的代码存在其他问题,但这是即时错误。快速概述其他问题:
foreach :: [a] → f → [r]
类型变量是隐式普遍量化的,因此这意味着任何类型f
。您需要更具体的类型,即a -> r
。
foreach x:[] f = (f x):[]
这是不必要的 - 递归案例在这里可以正常工作,将f
应用于x
并在尾部调用自身,给出空列表大小写。
foreach []:x f = []:(f x)
我认为这并不意味着你的意思 - 这是一个模式匹配列表的头部与空列表[]
,暗示该功能正在列表列表。
foreach (x:xs) f = (f x) : (foreach (xs f))
这里的括号不必要或不正确。同样,函数应用程序的优先级高于:
之类的运算符。此外,(xs f)
表示将xs
应用于f
,就像它是一个函数一样。要将foreach
应用于两个参数,只需foreach xs f
即可。
为了比较,这里是(参数顺序除外)标准库函数map
的源代码:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
答案 1 :(得分:3)
您提供的类型签名(至少在Haskell编译器看来)是假的。这是一个函数,它会获取任意a
的项目列表和任何类型f
的值,并生成任何的值列表输入r
。这就像是说“我有一堆大象和一把螺丝刀。把每只大象变成芒果”。
您的目标似乎是实现map
功能:
map :: (a -> b) -> [a] -> [b]
当然,翻转论点是完全有效的:
foreach :: [a] -> (a -> b) -> [b]
您的实施非常接近,但存在一些问题。
最重要的是要记住你正在使用列表,而不是数组。 :
运算符(也称为“cons”)接受一个项目并将其添加到列表中(例如1 : [2,3,4]
)。您不能像在[]:(f x)
中那样使用它来任意连接项目和列表。有++
运算符连接两个列表(例如[f x] ++ xs
,与(f x) : xs
相同),但您不需要它来实现foreach
。
最后,(foreach (xs f))
没有按照您的想法行事。它与C风格的语言不同foreach(xs,f)
,就像foreach(xs(f))
。 (xs f)
本身就像使用xs
作为函数并应用f
作为参数。相反,您需要(foreach xs f)
。
我会在这里停下来,以免过多放弃。但有一点点:电影应用程序的优先级高于任何操作符,因此可以说(f x) : (foreach xs f)
代替f x : foreach xs f
。
答案 2 :(得分:2)
您忘记将()
放入foreach []:x f = []:(f x)
并错误地指定了函数类型,现在应该编译以下内容:
foreach :: [a] -> (a -> r) -> [r]
foreach [] f = []
foreach (x:[]) f = (f x):[]
foreach (x:xs) f = (f x) : (foreach xs f)
并运行:
*Main> foreach [1..20] (+1)
[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]