0

I want to make function named headcol that works like:

headcol[[1,2],[3,4]] = [1,3]; 

So i made function like this:

fun headcol [] = [] 
  | headcol [x::xs',y::ys'] = [x,y]

but when I call it, I get a match nonexhaustive.

sshine
  • 15,635
  • 1
  • 41
  • 66
zion
  • 25
  • 4
  • *I want to make function named 'headcol'*, you should clarify what you want indeed. Your parameter is a list(which can have infinite elems), but you only math 2-elem list. That's what `nonexhaustive` means – Chen Li Nov 01 '18 at 04:00

2 Answers2

1

IIUC, headcol will extract all heads of lists in the parameter, whose type is 'a-list-list. What you mathc is only [] and [x::xs', y::ys'], not anything else. So, if your argument has more than 2 sublists, execption will raise:

- headcol[[1,2],[3,4], [4, 5, 9]]; 

uncaught exception Match [nonexhaustive match failure]
  raised at: a.sml:9.34
- 

If you just want to deal with two-elems list, pair is a better choice. Otherwise, you should match more cases:

fun headcol list =
    case list of
        [] => []
      | x::xs' =>
        case x of
            [] => headcol xs'
         |  h::t => h::(headcol xs')

output:

- headcol[[1,2],[3,4], [4, 5, 9]]; 
- val it = [1,3,4] : int list
Chen Li
  • 4,824
  • 3
  • 28
  • 55
1

As 陳 力 points out, it is hard to answer a question defined only by the name of a function and its attempted solution. Still, head sounds like you want to take the first element of each sub-list, and col sounds like you're treating this list of lists as a matrix with columns being orthogonal to to the sub-lists.

The recursive solution might also look like:

fun headcol [] = []
  | headcol ((x::_)::xss) = x :: headcol xss
  | headcol ([]::xss) = headcol xss

Here is how you might do it using built-in higher-order list combinators:

fun headcol xss =
    List.concat (List.map (fn xs => List.take (xs, 1)) xss)

The reason why I'm not simply doing:

fun headcol xss =
    List.map hd xss

is because hd is a partial function, so hd [] will crash at run-time.

On the other hand, List.take ([], 1) will return [].

And List.concat will combine the temporary result [[1],[2],[3]] into [1,2,3].

Or, in case a column is missing, [[1],[],[3]] into [1,3].

Test cases:

val test_headcol_0 = headcol [] = []
val test_headcol_1 = headcol [[1]] = [1]
val test_headcol_2 = headcol [[1,2],[3,4]] = [1,3]
val test_headcol_3 = headcol [[1,2,3],[4,5,6],[7,8,9]] = [1,4,7]
val test_headcol_4 = headcol [[1],[2,3],[4,5,6]] = [1,2,4]
val test_headcol_5 = headcol [[1],[],[2,3]] = [1,2]

Of course, I don't know if that's the behavior you expect from headcol with regards to irregular matrices that don't have a head column. This is a corner case you don't go into. In functional programming, you often embed error handling into the return value rather than throw exceptions.

So for example, you could want from headcol to return an 'a list option where SOME [1,4,7] suggests that each row did have a head column, and NONE suggests that at least one row failed to produce a column.

Or you could use a data type other than 'a list list to represent your matrix that does not allow rows with missing columns, e.g. an Array2.

sshine
  • 15,635
  • 1
  • 41
  • 66