初学者/学习者在haskell中实现foreach

时间:2011-01-19 15:28:17

标签: haskell pattern-matching

我正在尝试实现一个foreach态射,以便测试我对态射定义和模式匹配的理解......显然我完全错过了这两点。

你可以纠正我吗?我希望态射foreacha和态射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

3 个答案:

答案 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]