module Task5 open System type ChurchList<'a> = ('a -> 'b -> 'b) -> 'b -> 'b let nil : ChurchList<'a> = fun _ z -> z let cons (x: 'a) (xs: ChurchList<'a>) : ChurchList<'a> = fun f z -> f x (xs f z) let toList (churchList: ChurchList<'a>) : 'a list = churchList (fun x acc -> x :: acc) [] |> List.rev let ofList (lst: 'a list) : ChurchList<'a> = List.foldBack cons lst nil let countFrequencies (churchList: ChurchList<'a>) : ('a * int) list when 'a : equality = let regularList = toList churchList let rec countTailRec lst acc = match lst with | [] -> acc | x :: xs -> let rec updateCount freqList element = match freqList with | [] -> [(element, 1)] | (key, count) :: rest -> if key = element then (key, count + 1) :: rest else (key, count) :: updateCount rest element let newAcc = updateCount acc x countTailRec xs newAcc countTailRec regularList [] let findMaxFrequency (frequencies: ('a * int) list) : ('a * int) option = let rec findMaxTailRec lst currentMax = match lst with | [] -> currentMax | (element, count) :: rest -> match currentMax with | None -> findMaxTailRec rest (Some (element, count)) | Some (_, maxCount) -> if count > maxCount then findMaxTailRec rest (Some (element, count)) else findMaxTailRec rest currentMax findMaxTailRec frequencies None let findMostFrequent (churchList: ChurchList<'a>) : 'a option when 'a : equality = let frequencies = countFrequencies churchList match findMaxFrequency frequencies with | Some (element, _) -> Some element | None -> None let getMostFrequentCount (churchList: ChurchList<'a>) : int when 'a : equality = let frequencies = countFrequencies churchList match findMaxFrequency frequencies with | Some (_, count) -> count | None -> 0 [] let main argv = let testList1 = ofList [1; 2; 3; 2; 4; 2; 5; 3; 2] let frequencies1 = countFrequencies testList1 frequencies1 |> List.iter (fun (elem, count) -> printfn "%A: %d" elem count) match findMostFrequent testList1 with | Some element -> let count = getMostFrequentCount testList1 printfn "Most frequent: %A (%d times)" element count | None -> printfn "Empty list" let testList2 = ofList ["apple"; "banana"; "apple"; "cherry"; "banana"; "apple"] match findMostFrequent testList2 with | Some element -> let count = getMostFrequentCount testList2 printfn "Most frequent string: %A (%d times)" element count | None -> printfn "Empty list" let testList3 = ofList [5; 5; 5; 5] match findMostFrequent testList3 with | Some element -> let count = getMostFrequentCount testList3 printfn "All same: %A (%d times)" element count | None -> printfn "Empty list" let testList4 = ofList [1; 2; 3; 4; 5] match findMostFrequent testList4 with | Some element -> let count = getMostFrequentCount testList4 printfn "All unique, first: %A (%d times)" element count | None -> printfn "Empty list" let testList5 = nil match findMostFrequent testList5 with | Some element -> let count = getMostFrequentCount testList5 printfn "Should not happen: %A (%d times)" element count | None -> printfn "Empty list handled correctly" 0