英文:
Haskell: a function returning the last element of a list as a Maybe Just or Nothing on empty list
问题
我有这个简单的函数:
myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
这个函数的思路是,对于非空列表返回 Just x
,其中 x
是最后一个元素。如果列表为空,则返回 Nothing
。
现在,我缺少 lastHelper
的定义(上面的 myLast
必须 保持不变(这是一项作业)。
我已经尝试解决这个密码好几个小时了,但没有成功。我应该如何定义 lastHelper
?
英文:
I have this simple function:
myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
The idea is that it returns Just x
on an non-empty list with the last element x
. If the list is empty, Nothing
is expected.
Now, I am missing the definition of lastHelper
(the above myLast
must remain intact (this is homework)).
I tried to solve this cipher for hours now, to no avail. How should I go about defining lastHelper
?
答案1
得分: 3
以下是翻译好的部分:
考虑如何在不使用 foldr
的情况下递归解决这个问题:
myLast [] = Nothing
myLast (x:[]) = Just x
myLast (_:xs) = myLast xs
如果不是必须递归调用 myLast
,而是可以假设 myLast
将递归调用的结果作为参数接收呢?
-- 无法递归,所以忽略“神奇”的第二个参数
myLast' [] _ = Nothing
-- 返回 Nothing 的唯一方式是第一个参数为空,
-- 所以我们可以假设我们忽略的尾部为空
myLast' (x:_) Nothing = Just x
-- 如果达到这种情况,我们可以假设第一个列表有2个或更多元素。
-- x 显然不是最后一个元素,所以最后一个元素必须是尾部的最后一个元素,作为结果给出。
myLast' (x:_) result = result
注意,我们在这里不关心列表的尾部;我们假设“某人”将其用作给我们的第二个参数。
foldr
就是那个“某人”。我们通过仅接收列表的 头部 作为一个参数以及假定的递归结果作为第二个参数来推导出辅助函数。我们不再需要第一个情况:foldr
本身检测到空列表(没有头部),并在不使用辅助函数的情况下返回默认值。也就是说,只有在 myLast'
将会收到非空的第一个参数时,辅助函数才会被调用。
我将 myLast'
完全适应辅助函数的部分留给读者:
myLast xs = foldr lastHelper Nothing xs
where lastHelper ??? ??? = ???
lastHelper ??? ??? = ???
英文:
Consider how you might solve this recursively, without foldr
:
myLast [] = Nothing
myLast (x:[]) = Just x
myLast (_:xs) = myLast xs
What if, instead of having to call myLast
recursively, you could assume that myLast
receives the result of the recursive call as an argument?
-- No recursion possible, so ignore the "magical" second argument
myLast' [] _ = Nothing
-- The only way to return Nothing is with an empty first argument,
-- so we can assume the tail we are ignoring is empty
myLast' (x:_) Nothing = Just x
-- If we reach this case, we assume the first list has 2 or more
-- elements. x is clearly not the last one, so the last one must be
-- the last element of the tail, is given to as as the result.
myLast' (x:_) result = result
Notice that we never care about the tail of the list here; we assume that "someone" used it to give us our second argument.
foldr
is that someone. We derive the helper from myLast'
by receiving only the head of the list as one argument, and the presumed recursive result as the second. We no longer need the first case: foldr
itself detects the empty list (which has no head) and returns our default value without using the helper. That is, the helper only gets called when myLast'
would have received a non-empty first argument.
I leave the full adaptation of myLast'
to the helper to the reader.
myLast xs = foldr lastHelper Nothing xs
where lastHelper ??? ??? = ???
lastHelper ??? ??? = ???
答案2
得分: 2
When all else fails, expand a few cases and figure them out by hand:
foldr lastHelper Nothing []
is Nothing
by definition of foldr
.
Then,
foldr lastHelper Nothing (1::[])
--> lastHelper 1 (foldr lastHelper Nothing [])
--> lastHelper 1 Nothing [按照foldr的定义]
--> 我们希望这个结果是 Just 1,所以决定它是。
foldr lastHelper Nothing (2::1::[])
--> lastHelper 2 (foldr lastHelper Nothing (1::[]))
--> lastHelper 2 (Just 1) [根据之前的推测手动展开]
--> 结果也应该是 Just 1
foldr lastHelper Nothing (3::2::1::[])
--> lastHelper 3 (foldr lastHelper Nothing (2::1::[]))
--> lastHelper 3 (Just 1) [参考上面的情况]
--> 结果也应该是 Just 1 [我感觉有一个规律。]
现在你应该能够写下:
lastHelper x Nothing = ???
lastHelper x ??? = ???
并填写这些空白部分。
英文:
When all else fails, expand a few cases and figure them out by hand:
foldr lastHelper Nothing []
is Nothing
by definition of foldr
.
Then,
foldr lastHelper Nothing (1::[])
--> lastHelper 1 (foldr lastHelper Nothing [])
--> lastHelper 1 Nothing [By definition of foldr]
--> We wish this to be Just 1, so decide that it is.
foldr lastHelper Nothing (2::1::[])
--> lastHelper 2 (foldr lastHelper Nothing (1::[])
--> lastHelper 2 (Just 1) [By the previous wishful hand-expansion]
--> Should be Just 1, as well
foldr lastHelper Nothing (3::2::1::[])
--> lastHelper 3 (foldr lastHelper Nothing (2::1::[])
--> lastHelper 3 (Just 1) [See above]
--> Should also be Just 1 [I sense a pattern here.]
Now you should be able to write down
lastHelper x Nothing = ???
lastHelper x ??? = ???
and fill in the blanks
答案3
得分: 1
foldr
是对列表的一个折叠操作。实际上,它将 foldr f z
用 (:)
替换为 f
,用 []
替换为 z
。
因此,这意味着你可以让 f
检查第二个参数。如果它是 Nothing
,我们知道第一个参数是最后一个项目,如果是 Just
,我们知道第一个参数不是最后一个项目,因此我们传播最后一个项目。
因此,函数看起来像:
myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
where lastHelper x Nothing = ... -- x 是最后一个项目
lastHelper x (Just y) = ... -- x 不是最后一个项目
在上面的代码中,你需要填写 <code>...</code>
部分作为练习。
英文:
foldr
is a catamorphism on a list. Indeed, it foldr f z
replaces (:)
with f
and []
with z
.
This thus means that you can let f
inspect the second parameter. If it is a Nothing
we know that the first parameter is the last item, if it a Just
we know that the first parameter is not the last item, so we propagate the last one.
The function thus will look like:
<pre><code>myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
where lastHelper x Nothing = … -- x is the last item
lastHelper x (Just y) = … -- x is not the last item</code></pre>
where I leave filling in the <code>…</code> parts as an exercise.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论