Get the min element from a list of dates (operator is not a function [tycon mismatch])

StackOverflow https://stackoverflow.com/questions/19342769

  •  30-06-2022
  •  | 
  •  

Question

I wonder, how can I find the oldest date in a list:

fun the_oldest_date(date_list: (int * int * int) list) = 
  let
    (*it might be useful*)
    fun older_date(date1: (int * int * int), date2: (int * int * int)) = 
      if #1 date1 < #1 date2 andalso
         #2 date1 < #2 date2 andalso
         #3 date1 < #3 date2
      then date1
      else date2
  in
    if null date_list
    then NONE
    else SOME older_date(hd date_list, the_oldest_date(tl date_list))
  end

I'd like not to use any library functions here, only recursion and standard ML facilities. And I get the error

Error: operator is not a function [tycon mismatch]
  operator: ((int * int * int) * (int * int * int) -> int * int * int) option
in expression:
  (SOME older_date) (hd date_list,the_oldest_date (tl date_list))
/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0
Was it helpful?

Solution

Alex,

your older_date function is not working right. You didn't consider two dates that have same year and/or month (ie. (1,1,1) and (1,1,2)). And finally this function should return bool not a (int * int * int).

Finding a maximum is a bit trickier, so you should try to find the maximum of a list tail and then compare it with a head.

I hope this helps. And my code is:

fun the_oldest_date(date_list : (int * int * int) list) : (int * int * int) option = 
    let 
        fun older_date(date1:(int * int * int) , date2:(int * int * int)) : bool =
            if #1 date1 < #1 date2 
            then true
            else if #1 date1 = #1 date2
                 then if #2 date1 < #2 date2 
                      then true
                      else if #2 date1 = #2 date2
                           then if #3 date1 < #3 date2 
                                then true
                                else false
                           else false
                 else false  
     in        
        if null date_list 
        then NONE
        else
            let
                val prevMax = the_oldest_date(tl date_list)
            in
                if prevMax = NONE
                then SOME(hd date_list)
                else if older_date(hd date_list, valOf prevMax)
                     then SOME(hd date_list)
                     else prevMax
            end
    end

OTHER TIPS

There are three issues.

First, you forgot brackets in

SOME older_date(hd date_list, the_oldest_date(tl date_list))

as SML tells you, this is interpreted as

(SOME older_date) (hd date_list, the_oldest_date(tl date_list))

and SOME older_date isn't a function.

Since older_date has type

(int * int * int) * (int * int * int) -> int * int * int 

SOME older_date has type

((int * int * int) * (int * int * int) -> int * int * int) option

You should make it

SOME (older_date(hd date_list, the_oldest_date(tl date_list)))

(Function application associates to the left, so a b c means (a b) c, not a (b c).

Except that this won't work either, because of the second issue.

The second issue is that the_oldest_date returns an int * int * int option, while older_date expects an int * int * int (you might want to consider a more specific data type - it's impossible to tell which part of a date is which here).
You'll need to check the result of the_oldest_date (tl date_list) to see if it actually returns something before you pass it to the comparison function.

The third issue is that your date comparison is a bit funky.
As far as I can see, you claim that there is no date ever that is earlier than January 1st, 2014.
I have my doubts about that.

sml is complaining because you're using option type. 'a option = NONE | SOME of 'a i.e. the argument in (SOME older_date)... should be a single element, which should be your oldest date.

ok. first things first, remove the last andalso inside older_date.

I'd convert each date to an epoch, then compare the ints. Something like

epoch = (#1 date-1) * 365 + daysBeforeMonth(#2 date) + (#3 date)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top