доступ к кортежу: не удается найти фиксированный тип записи

Я написал функцию, которая должна получать список кортежей. Я обращаюсь к компонентам кортежей с помощью #, и код компилируется:

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 validate ([]) = true
  | validate (h::t)  = 
    if 1 = (#1 h) then
    true
    else
    false

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

В чем здесь разница и почему последний вызывает ошибку?

Редактировать

Первая функция на самом деле не компилируется сама по себе.

Но весь этот фрагмент делает:

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
  )

person lo tolmencre    schedule 28.04.2016    source источник


Ответы (2)


Ваш первый код не компилируется, по крайней мере, с SML/NJ:

введите здесь описание изображения

Если вы получили его для компиляции, то он должен быть в нестандартном расширении SML.

Проблема с обоими вашими определениями заключается в том, что в SML нет полиморфной идеи tuple произвольной арности. Вы можете написать функции для работы со списками пар. Вы можете написать функции для работы со списками троек. Но -- вы не можете писать функции для одновременной работы со списками пар и списками троек (по крайней мере, если ваша функция пытается работать с этими парами/тройками как с кортежами).

Одним из решений является избавление от # и использование сопоставления с образцом для извлечения компонентов:

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

Но если вы действительно хотите написать функцию, которая может полиморфно применяться либо к спискам пар, либо к спискам троек (или четверок,...), проще всего представить пары, тройки и т. д. в виде списков, а чем кортежи. Списки, которые содержат списки неопределенного размера, не являются проблемой в SML.

person John Coleman    schedule 28.04.2016
comment
Вы правы, он не компилируется сам по себе. Но при вызове из другой функции это происходит... странно. Я отредактировал свой стартовый пост с дополнительным кодом, который заставляет его компилироваться. - person lo tolmencre; 28.04.2016
comment
Я также не могу заставить отредактированную версию скомпилироваться. Что такое drop? Может случиться так, что если у вас есть компиляция всего файла и в некоторых определениях функций достаточно информации о типах, чтобы устранить двусмысленность из других определений функций, то некоторые компиляторы, по крайней мере, допускают это. Какой компилятор вы используете? - person John Coleman; 28.04.2016
comment
Извините, я забыл включить метод drop, я скомпилировал файл, и он работал, но только потому, что я загрузил drop из предыдущей компиляции... Я еще не знал, что функция будет запоминаться, когда они будут скомпилированы один раз во время сеанса . Я использую PolyML. - person lo tolmencre; 28.04.2016
comment
Должно быть расширение PolyML. SML/NJ по-прежнему не нравится (хотя я загружал его через use, а не через не очень простой в использовании менеджер компиляторов). - person John Coleman; 28.04.2016

Попытка минимизировать это, так как я видел следующую работу в SML/NJ, и я не знаю, что это на самом деле расширение компилятора

val p1 = {x=0, y=0};
val p2 = {x=1, y=1};
val p3 = {x=1, y=1, z=1};

Существует неудобная конструкция с точки зрения ошибки компилятора, не во многих языках есть ошибки, которые работают таким образом, потому что функция действительна, но выдает ошибку типа, если не существует вызова функции для разрешения типа «запись», таким образом, чтобы устранить ошибку, необходимо добавить дополнительный код.

fun getFoo(field) = fn record => field record;

Без последующего фактического вызова getX компилятор не может определить тип record, для которого компилятору должна быть известна полная информация о типе ВСЕХ полей записи, а не только поля #x.

let val getX = getFoo(#x);
    val x1 = getX(p1);
    val x2 = getX(p2);
    val x3 = getFoo(#x)(p3);
in () end;

в то время как следующий закомментированный фрагмент приводит к ошибке, потому что типы p1 и p3 различны, и поэтому требуются разные вызовы getFoo

(*
let val getX = getFoo(#x);
    val x1 = getX(p1);
    val x3 = getX(p3);
in () end;
*)

и следующего недостаточно, так как он никогда не разрешает запись.

let val getX = getFoo(#x) in () end;
person matt    schedule 01.05.2016