Search code examples
tuplessmlrecords

tuple access: Can't find a fixed record type


I wrote a function that is supposed to receive a list of tuples. I access the components of the tuples with # and the code compiles:

fun recheck ([], n) = []
  | recheck (h::t, n) = 
    if ((#1 h) *  (#1 h)) +  ((#2 h) * (#2 h)) = n then
    h::recheck(t, n)
    else
    recheck(t, n)

But another function that basically does the same thing, namely receiving a list of tuples and accessing those, causes an error.

fun validate ([]) = true
  | validate (h::t)  = 
    if 1 = (#1 h) then
    true
    else
    false

Can't find a fixed record type.   Found near #1

What is the difference here and why does the latter cause an error?

Edit

The first function actually does not compile on its own.

But this entire snippet does:

fun drop ([], n) = []
  | drop (h::t, 0) = h::t
  | drop (h::t, n) =
    drop(t, n-1) 

fun sts_linear (y, n) =
  if y < (Math.sqrt(n)+1.0) then
      let
      (* x^2 + y^2 = n => x = sqrt(n-y^2) *)
      val x = Math.sqrt(n - (y * y));
      val xr  = Real.realRound(x);
      in
  if (abs(x - xr) < 0.000000001)  then
          [(Real.trunc xr, Real.trunc y)]@sts_linear (y+1.0, n)
      else
          (
        []@sts_linear (y+1.0, n)
          )
      end
  else []

fun recheck ([], n) = []
  | recheck (h::t, n) =
    if ((#1 h) *  (#1 h)) +  ((#2 h) * (#2 h)) = n then
    h::recheck(t, n)
    else
    recheck(t, n)

fun sts (n) =
  (
    let
        val pairs = sts_linear(0.0, Real.fromInt n);
    in
        recheck(drop(pairs, Real.ceil( Real.fromInt (length(pairs))/2.0 ) ), n)
    end
  )

Solution

  • Your first code doesn't compile, at least with SML/NJ:

    enter image description here

    If you got it to compile then it must have been in a nonstandard extension of SML.

    The problem with both of your definitions is that there is no polymorphic idea of a tuple of arbitrary arity in SML. You can write functions to work on lists of pairs. You can write functions to work on lists of triples. But -- you can't write functions to work simultaneously on lists of pairs and lists of triples (at least if your function tries to do things with these pairs/triples as tuples).

    One solution is to get rid of # and use pattern-matching to extract the components:

    fun validate [] = true
    |   validate ((x,y)::t)  = 
            if x = 1 then
                true
            else
                false
    

    But, if you really want to write a function which can polymorphically apply to either lists of pairs or list of triples (or quadruples,...), the easiest thing to do is to represent the pairs, triples, etc. as lists rather than tuples. Lists which contains lists of nonspecified size are not a problem in SML.