Haskell: a function returning the last element of a list as a Maybe Just or Nothing on empty list

huangapple go评论73阅读模式
英文:

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] -&gt; Maybe a
myLast xs = foldr lastHelper Nothing xs
where lastHelper x Nothing = &hellip; -- x is the last item
lastHelper x (Just y) = &hellip; -- x is not the last item</code></pre>

where I leave filling in the <code>&hellip;</code> parts as an exercise.

huangapple
  • 本文由 发表于 2023年5月25日 20:31:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定