Search code examples
smlsmlnj

SML - Using map to return combined results


I have these functions:

fun IsDivisible(t, t2) = if t mod t2 > 0 then true else false;

fun IsDivisibleFilter(ts, t) = List.filter(fn x => IsDivisible(x, t)) ts;

fun IsDivisibleMap(ts, ts2) = map(fn x => IsDivisibleFilter(ts, x)) ts2;

IsDivisibleMap - Takes two lists of ints, ts, and ts2, and returns a list containing those elements of ts that are indivisible by any elements in ts2.

E.g. IsDivisibleMap([10,11,12,13,14],[3,5,7]) should return [11,13].

The way I have it now it is returning a list of lists, where each list is the result for each number in ts2

E.g. IsDivisibleMap([10,11,12,13,14],[3,5,7]) is returning [10,11,13,14][11,12,13,14][10,11,12,13]

How can I return the result that I am looking for while still using map and filter wherever possible?


Solution

  • There are various problems here with terminology; I'd like to begin by addressing those.

    First, the name IsDivisibleMap is not a good name for two reasons:

    1. Based on the description of the function, it is a filter, not a map. That is, given an input list, it removes elements from that list which do not satisfy a predicate.
    2. The elements produced by this function are indivisible by all elements of the second input.

    Based on these considerations, I'd like to call the function IsIndivisibleFilter instead. I will also change the name IsDivisible to IsIndivisible.

    Second, in your description of the function, you say that it should return a list containing those elements of ts that are indivisible by any elements in ts2. However, I think what you meant is: "return a list containing those elements of ts that are indivisible by all elements in ts2"


    Now, back to the main problem. For each element of ts, we need to check that it is indivisible by all of the elements of ts2. There is a nice function called List.all which checks if all elements of a list satisfy some predicate. So to check a particular element t of ts, we could do:

    fun IsIndivisibleByAll (t, ts2) = 
      List.all (fn t2 => IsIndivisible (t, t2)) ts2
    

    Now we can implement the original function by filtering according to this predicate:

    fun IsIndivisibleFilter (ts, ts2) =
      List.filter (fn t => IsIndivisibleByAll (t, ts2)) ts
    

    Finally, I'd like to mention that you could clean up this implementation quite a bit with proper currying. Here's how I would implement it:

    fun IsIndivisible t t2 = (t mod t2 > 0)
    fun IsIndivisibleByAll ts2 t = List.all (IsIndivisible t) ts2
    fun IsIndivisibleFilter (ts, ts2) = List.filter (IsIndivisibleByAll ts2) ts