初学者/学习者在 haskell 中实现 foreach
我正在尝试实现一个 foreach 态射,以测试我对态射定义和模式匹配的理解......显然我完全错过了这两点。
你能纠正我吗?我希望态射 foreach
将 a
列表和态射 f
作为参数,并返回所有结果的列表
应用于所有 f
的 ra
元素。
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
I am trying to implement a foreach morphism so as to test my understanding of morphism definition and pattern-matching... Obviously I miss both points completely.
Could you correct me ? I want the morphism foreach
to takes a list of a
and a morphism f
as arguments and to return the list of all the results r
of f
applied to all a
elements.
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))
When compiled, I have src\Main.hs:23:0: Parse error in pattern
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
问题在于语法,在这一行中:
模式中的构造函数应用程序通常需要加上括号。这会起作用:
顺便说一句...函数应用程序具有最高优先级,因此另一方面,您不需要在右侧使用括号:
上面的内容适用于任何中缀构造函数,但作为最后的说明,特别是对于列表有一种特殊的语法:
您的代码目前还存在其他问题,但这是立即出现的错误。其他问题的快速概述:
类型变量是隐式通用量化的,因此这意味着任何类型
f
。您需要一个更具体的类型,即a ->; r
。这是不必要的——递归情况在这里将正常工作,将
f
应用到x
并在尾部调用自身,给出空列表情况。我不认为这意味着你所认为的意思——这是将列表头与空列表
[]
进行匹配的模式,这意味着该函数正在处理列表列表。这里的括号要么是不必要的,要么是不正确的。同样,函数应用程序的优先级高于
:
等运算符。此外,(xs f)
表示将xs
应用于f
,就好像它是一个函数一样。要将foreach
应用于两个参数,只需foreach xs f
就足够了。为了进行比较,以下是标准库函数
map
的源代码(除了参数顺序外,其他均相同):The problem is syntactic, in this line:
Constructor application in patterns usually need to be parenthesized. This would work:
Incidentally... function application is highest precedence, so on the other hand you don't need parentheses on the right-hand side:
The above holds for any infix constructor, but as a final note, for lists in particular there is a special syntax:
There are other issues with your code as it stands, but that's the immediate error. A quick overview of the other problems:
Type variables are implicitly universally quantified, so this means any type
f
. You need a more specific type, namelya -> r
.This is unnecessary--the recursive case will work correctly here, applying
f
tox
and calling itself on the tail, giving the empty list case.I don't think this means what you think it means--this is pattern matching the head of a list against the empty list
[]
, implying that the function is working on a list of lists.The parentheses here are either unnecessary or incorrect. Again, function application has higher precedence than operators like
:
. Additionally,(xs f)
means applyingxs
tof
, as if it were a function. To applyforeach
to two arguments, simplyforeach xs f
will suffice.For comparison, here's the source code for the (identical except for argument order) standard library function
map
:你给出的类型签名(至少在 Haskell 编译器看来)是假的。它是一个函数,它接受任何
a
的项目列表和 any 类型f
的值,并生成 f 的值列表>任意类型r
。这就像说“我有一群大象和一把螺丝刀。将每头大象变成芒果”。看来您的目标是实现
map
函数:当然,翻转参数是完全有效的:
您的实现非常接近,但存在一些问题。
最重要的是要记住,您正在使用列表,而不是数组。
:
运算符也称为“cons”,它获取一个项目并将其添加到列表中(例如1 : [2,3,4]
)。您不能使用它来任意连接项目和列表,就像在[]:(fx)
中所做的那样。有++
运算符连接两个列表(例如[fx] ++ xs
,与(fx) : xs
相同) ),但您不需要它来实现foreach
。最后,
(foreach (xs f))
并没有像你想象的那样做。它不像 C 风格语言中的foreach(xs,f)
,而是像foreach(xs(f))
。(xs f)
本身就像使用xs
作为函数并应用f
作为参数。相反,您需要(foreach xs f)
。我将在这里停下来,以避免透露太多。不过有一点:函数应用程序的优先级高于任何运算符,因此您可以使用
fx : foreach xs f
来代替(fx) : (foreach xs f)
。The type signature you give, is (at least in the Haskell compiler's opinion) bogus. It's a function which takes a list of items of any
a
and a value of any typef
, and produces a list of values of any typer
. It's like saying "I have a bunch of elephants and a screwdriver. Turn each elephant into a mango".It seems your goal is to implement the
map
function:Of course, it's perfectly valid to flip the arguments:
Your implementation is pretty close, but there are a few issues.
The biggest thing is to bear in mind that you're working with lists, not arrays. The
:
operator, also known as "cons", takes an item and prepends it to a list (e.g.1 : [2,3,4]
). You can't use it to arbitrarily concatenate items and lists, as you do in[]:(f x)
. There is the++
operator which concatenates two lists (e.g.[f x] ++ xs
, which is the same as(f x) : xs
), but you shouldn't need it to implementforeach
.Lastly,
(foreach (xs f))
doesn't do what you may think it does. It is not likeforeach(xs,f)
in a C-style language, it is likeforeach(xs(f))
.(xs f)
, by itself, is like usingxs
as a function and applyingf
as the argument. Instead, you want(foreach xs f)
.I will stop here, to avoid giving away too much. One little tidbit though: function application has higher precedence than any operator, so instead of
(f x) : (foreach xs f)
, you can sayf x : foreach xs f
.您忘记将
()
放入foreach []:xf = []:(fx)
中并错误地指定了函数类型,现在应该编译以下内容:并运行:
You've forgot to put
()
inforeach []:x f = []:(f x)
and incorrectly specified the function type, the following should now compile:and run:
只是一个小附录。除了递归模式匹配之外,还可以通过使用列表理解以干净的方式实现
foreach
:就是这样。
Just a small addendum. Aside from recursive pattern matching, one can also implement
foreach
in a clean way by using list comprehension:That's it.