简体   繁体   English

Haskell中的显式递归

[英]Explicit recursion in Haskell

The task: I'm attempting to write a function with type signature minimum_recursive :: (a -> a -> Bool) -> [a] -> a . 任务:我正在尝试编写一个带有类型签名minimum_recursive :: (a -> a -> Bool) -> [a] -> a的函数。 For its first parameter, it accepts a function I will call less that takes two parameters, and returns True if the first param is less than the second, False otherwise. 对于它的第一个参数,它接受一个我将调用less的函数,它接受两个参数,如果第一个参数小于第二个参数,则返回True,否则返回False。 minimum_recursive also accepts a list as its second parameter. minimum_recursive还接受列表作为其第二个参数。 Using explicit recursion, minimum_recursive should determine the smallest value in its input list [a]. 使用显式递归, minimum_recursive应确定其输入列表中的最小值[a]。

My thinking: I was thinking to put the actual recursion in a helper function that also accepts an accumulator. 我的想法:我正在考虑将实际的递归放在一个也接受累加器的辅助函数中。 I would call the helper function with the first item as the accumulator. 我将第一个项目作为累加器调用辅助函数。

What I have so far: So far I have the following: 我至今:到目前为止,我有以下几点:

-- function as first parameter to min'
-- accepts two params, returns True if
-- first must come before second in sorted
-- order
less :: Ord a => a -> a -> Bool
less a b = a < b

-- Subpart B
minimum_recursive :: (a -> a -> Bool) -> [a] -> a
minimum_recursive func list = minimum_recursive_h func list []

I am having trouble figuring out how to even begin to write minimum_recursive_h . 我无法弄清楚如何开始编写minimum_recursive_h

Note: I know there probably is an easier way to accomplish this task, but I'm required to go about it as specified above. 注意:我知道可能有更简单的方法来完成此任务,但我需要按照上面的说明进行操作。

You could do it like this: 你可以这样做:

minimum_recursive _ [] = error "no minimum of empty list"
minimum_recursive _ [x] = x
minimum_recursive f (x:xs) = let m = minimum_recursive f xs
                             in if f x m then x else m

Or, with an accumulator: 或者,使用累加器:

minimum_recursive _ [] = error "no minimum of empty list"
minimum_recursive f (x:xs) = helper f x xs
    where
      helper _ m [] = m
      helper f m (x:xs) 
          | f m x = helper f m xs
          | otherwise = helper f x xs

If you want the smallest ellement in the list I sugest that you add the smallest ellement you currently have as a parameter to the function. 如果你想要列表中最小的元素,我会把你当前拥有的最小元素作为参数添加到函数中。

minimum_recursive :: (a -> a -> Bool) -> a -> [a] -> a
minimum_recursive f min [] = min
minimum_recursive f min (x:xs) | f min x   = minimum_recursive f min xs
                               | otherwise = minimum_recursive f x   xs

You should also change the type in the function that call this from a to Maybe a since there are no smallest ellement in an empty list. 您还应该将调用此函数的函数中的类型从a更改为Maybe a因为空列表中没有最小元素。 Here some help about Maybe 这里有一些关于Maybe的帮助

If you want to do it without an extra parameter you could store the smallest ellement in the beginning of the list ass well. 如果你想在没有额外参数的情况下这样做,你可以将最小的元素存储在列表的开头。 In this case it's important to use Maybe 在这种情况下,使用Maybe非常重要

minimum_recursive :: (a -> a -> Bool) -> [a] ->Maybe a
minimum_recursive f [] = Nothing
minimum_recursive f (x:[]) = Just x
minimum_recursive f (y:(x:xs)) | f y x     = minimum_recursive f (y:xs)
                               | otherwise = minimum_recursive f (x:xs)

This is how the minumum can be found ehit fold. 这就是如何找到最小的折叠。 Look at the beauty of functionall programming. 看看functionall编程的美妙之处。 But this wont work for the empty list 但这不适用于空列表

simplefold :: [a] -> a
simplefold (x:xs) = foldl min x xs  

But we can embed this function in one that checks if the list is empty and return Nothing in that case. 但是我们可以将这个函数嵌入到一个检查列表是否为空的函数中,并在这种情况下返回Nothing。

betterfold :: [a] -> Maybe a
betterfold [] = Nothing
beterfold l   = Just (simplefold l)

The classic way to solve problems recursively is the following: 递归解决问题的经典方法如下:

  1. Assume you've nearly solved the problem, except for the final step. 假设你几乎解决了这个问题,除了最后一步。
  2. Write the code that, given the solution for all except that final step, computes the solution produced by that final step. 编写代码,给出除最后一步之外的所有解决方案,计算最后一步产生的解决方案。
  3. Write the base case. 写下基本案例。

In the case of lists, this translates to this pattern: 在列表的情况下,这转换为这种模式:

  1. Base case: what should the solution be for [] ? 基本情况: []的解决方案应该是什么? (if anything; in the case of your minimum_recursive function, this would be an error). (如果有的话;在你的minimum_recursive函数的情况下,这将是一个错误)。
  2. For a nonempty list x:xs , assume you already have almostTheResult = minimum_recursive f xs . 对于非空列表x:xs ,假设您已经有almostTheResult = minimum_recursive f xs How do you compute minimum_recursive (x:xs) given that? 你如何计算minimum_recursive (x:xs)呢?

I'll give you a big hint: your minimum_recursive can be implemented in terms of foldr and this function: 我会给你一个很大的提示:你的minimum_recursive可以用foldr和这个函数来实现:

minBy :: (a -> a -> Bool) -> a -> a -> a
minBy pred x y = if pred x y then x else y

The foldr function does exactly what I'm describing above. foldr函数正如我上面所描述的那样。 The first argument to foldr is the function that computes the final solution given the list head and the partial solution for the tail, and the second argument is the result base case. foldr的第一个参数是在给定列表头和尾部的部分解决方案的情况下计算最终解的函数,第二个参数是结果基本情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM