Search code examples
smlsmlnj

SML/NJ searching in list of tuples of list


I am very new to SML/NJ and I am kind of lost. I have been trying to implement a function that is going to search through the list of tuples that have some lists in it, for example:

val x = [(5, 2, [9 , 8, 7]), (3, 4, [6, 5, 0]), (11, 12, [8, 3, 1])] 

I would like my function to add the first element of the tuple to the new list once there is a match between my target number and a number in element 3 of the tuple. I have tried several implementations, but none of them work properly so far.

type id = int* int* int list;
val b:id list = [(5,2,[9,8,7]), (3,4,[6,5,0]), (11, 12, [8,3,1])]
val number: int = 8;
val a: int list = nil;

fun findNum(nil) = a | findNum (x: id list) =
    let val tem = hd(x)
        val theList = #3tem
        val i = #1tem
        fun findMatch(nil) = a | findMatch(tem) =
            if (number = hd(theList)) then i::a 
            else findMatch (tl(theList))
    in findNum(tl(x))
    end;

 findNum(b);

I know it is badly written, and that is why it keeps returning an empty list. I feel like I need to do "if else" instead of let/in/end so it will recursively call the rest of the tuples in the list. My problem is that I am not sure how to do it because if I use if/else then I cannot declare some value inside the function. I appreciate any suggestions or hints.

Thank you.


Solution

  • You might start with a function member (x, xs) that is true if x is an element in the list xs:

    fun member (x, xs) = List.exists (fn y => x = y) xs
    

    A base case is when the list of three-tuples is empty. Then x does not occur in the third element of any of the (non-existing) three-tuples, and the list of results is empty. A recursive case is achieved by pattern matching against the first element of the list being a three-tuple, (i,j,xs), and the tail of the list, ts, and ask if x is a member of that third element xs; if it is, return the first part of the tuple, i:

    fun find (x, []) = []
      | find (x, (i,j,xs)::ts) =
        if member (x, xs)
        then i :: find (x, ts)
        else find (x, ts)
    

    A shorter version using the higher-order list combinators map and filter:

    fun find (x, ts) = map #1 (filter (fn (i,j,xs) => member (x, xs)) ts)