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

发布于 2024-10-12 12:08:50 字数 451 浏览 1 评论 0原文

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

你能纠正我吗?我希望态射 foreacha 列表和态射 f 作为参数,并返回所有结果的列表 f 的 r 应用于所有 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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黑寡妇 2024-10-19 12:08:50

问题在于语法,在这一行中:

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

The problem is syntactic, in this line:

foreach x:[] f = (f x):[]

Constructor application in patterns usually need to be parenthesized. This would work:

foreach (x:[]) f = (f x):[]

Incidentally... function application is highest precedence, so on the other hand you don't need parentheses on the right-hand side:

foreach (x:[]) f = f x:[]

The above holds for any infix constructor, but as a final note, for lists in particular there is a special syntax:

foreach [x] f = [f x]

There are other issues with your code as it stands, but that's the immediate error. A quick overview of the other problems:

foreach :: [a] → f → [r]

Type variables are implicitly universally quantified, so this means any type f. You need a more specific type, namely a -> r.

foreach x:[] f = (f x):[]

This is unnecessary--the recursive case will work correctly here, applying f to x and calling itself on the tail, giving the empty list case.

foreach []:x f = []:(f x)

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.

foreach (x:xs) f = (f x) : (foreach (xs f))

The parentheses here are either unnecessary or incorrect. Again, function application has higher precedence than operators like :. Additionally, (xs f) means applying xs to f, as if it were a function. To apply foreach to two arguments, simply foreach xs f will suffice.


For comparison, here's the source code for the (identical except for argument order) standard library function map:

map :: (a -> b) -> [a] -> [b]
map _ []     = []
map f (x:xs) = f x : map f xs
下壹個目標 2024-10-19 12:08:50

你给出的类型签名(至少在 Haskell 编译器看来)是假的。它是一个函数,它接受任何 a 的项目列表和 any 类型 f 的值,并生成 f 的值列表>任意类型r。这就像说“我有一群大象和一把螺丝刀。将每头大象变成芒果”。

看来您的目标是实现 map 函数:

map :: (a -> b) -> [a] -> [b]

当然,翻转参数是完全有效的:

foreach :: [a] -> (a -> b) -> [b]

您的实现非常接近,但存在一些问题。

最重要的是要记住,您正在使用列表,而不是数组: 运算符也称为“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 type f, and produces a list of values of any type r. 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:

map :: (a -> b) -> [a] -> [b]

Of course, it's perfectly valid to flip the arguments:

foreach :: [a] -> (a -> b) -> [b]

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 implement foreach.

Lastly, (foreach (xs f)) doesn't do what you may think it does. It is not like foreach(xs,f) in a C-style language, it is like foreach(xs(f)). (xs f), by itself, is like using xs as a function and applying f 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 say f x : foreach xs f.

耳钉梦 2024-10-19 12:08:50

您忘记将 () 放入 foreach []:xf = []:(fx) 中并错误地指定了函数类型,现在应该编译以下内容:

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]

You've forgot to put () in foreach []:x f = []:(f x) and incorrectly specified the function type, the following should now compile:

foreach :: [a] -> (a -> r) -> [r]
foreach [] f = []
foreach (x:[]) f = (f x):[]
foreach (x:xs) f = (f x) : (foreach xs f)

and run:

*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]
守不住的情 2024-10-19 12:08:50

只是一个小附录。除了递归模式匹配之外,还可以通过使用列表理解以干净的方式实现 foreach

foreach aList f = [ f a | a <- aList ]

就是这样。

Just a small addendum. Aside from recursive pattern matching, one can also implement foreach in a clean way by using list comprehension:

foreach aList f = [ f a | a <- aList ]

That's it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文