简体   繁体   中英

F# find minimum function with List.fold

I need a function that finds the minimum element of a list implementing the List.fold module. I know I can use List.min but for this exercise I need it to be List.fold. So far I have:

let findMin list min = function
     | [ ] -> min
     | head::tail ->  list |> List.fold( fun acc -> min)  //missing conditional inside fold to determine min

I'm not used to functional programming, normally in java I'd do something like this:

 public int getMin (){

  int min = head.data;
  Node curr = head.next;

  while (! ( curr  == NULL ) ){
     if ( curr.data < min) 
          min = curr.data;

      curr = curr.next; 
   }

   return min;
 }

But since F# works with immutable constants I can't reassign min. I've found examples of fold used to count or sum elements in a list but none that find a minimum or maximum element. I'm having trouble specifically with the conditional logic inside of the module, if anyone can help me I'd greatly appreciate it. Thank you in advance.

You don't need to deal with the case where the input list is empty because List.fold returns the initial value in that case. Normally we pass System.Int32.MaxValue as the initial value.

Here is long-version code:

let min a b = if a < b then a else b

let minOfList initialValue theList =
    theList
    |> List.fold
        (fun currentMin x ->
            let newMin = min currentMin x
            newMin)
        initialValue

let result = minOfList System.Int32.MaxValue [34; -1; 21; 99]
printfn "%d" result // -1

And short-version code:

let min a b = if a < b then a else b
let minOfList = List.fold min
let result = minOfList System.Int32.MaxValue [34; -1; 21; 99]
printfn "%d" result // -1

The concept of fold is simple: you iterate a function called the folder function over a list. In each call the folder function receives an element from the list and a state and it returns an updated state.

That is very similar to your imperative code: you are iterating over a list, receiving an element from the list and the old value of variable min and after each iteration you have a new value of min . The difference with imperative programming is the folder function does not change the state, instead it receives one an returns another one, you can imagine if you like that List.fold changes a variable internally.

The signature of fold is:

List.fold :
   folder: 'State -> 'T -> 'State ->
   state : 'State  ->
   list  : 'T list 
        -> 'State

the first parameter is a folder function, the second is an initial state and the third is the list of elements. The result is going to be the last state.

So your folder function should look something like this:

let folder min currData = ...

and your minimum function should look like this:

let minimum ls =
    ls
    |> List.fold folder initial

and you call it like this:

minimum [ 5 ; 3 ; 8]
|> printfn "%A"  // outputs: 3

There are some questions left about how to deal with the initial value and what happens if the list is empty. But I will leave those to you.

Hope this helps.

You can use the accumulator as the value that you would normally assign the minimum value to.

For each item of the array, fold feeds the accumulator and the current item to a given function. Whatever is returned by that function becomes the new accumulator value.

Using the built-in min function you can write

let findMin list = List.fold min System.Int32.MaxValue list

min is the function being applied to each item and the accumulator

System.Int32.MaxValue is the original value of the accumulator, the seed

You could also use List.reduce which is the same thing but it uses the first element of the list as a seed.

let findMin list = List.reduce min list

Ideally you would wrap this in something that handles the empty array case because fold will return the seed value and reduce will raise an exception.

Thank you to all for your help, to clear up some concepts. This is the final running snippet, the input validation is done in the main function.

// this is the folder function List.fold calls, receives the current min and item
let folder a b = if a < b then a else b

// recieves a list and returns the minimum using the List.fold module
let fold  list = List.fold (fun acc elem -> folder acc elem) (List.head list) list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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