2016-05-08 8 views
0

Я нахожусь на своих первых этапах программирования и в sml. Я пытаюсь создать программу. На самом деле происходит множество ошибок. В этой статье мне нужна ваша ценная помощь для ошибки «оператор не является функцией» Я новичок в функциональном программировании, и мне трудно понять его логику. Могу ли я использовать несколько объявлений val в let? Is let/val/in использован в шаблоне сопоставив? Спасибо!Оператор не является функцией-sml

fun action(_,_,[]) = ([],[]) 
    |action(cin,cout,h::[]) = 
    let 
     val (s1,d1,d2) = (pass_cout(pass_cin h cin) cout, #1   (find2digits((pass_cout(pass_cin h cin) cout))),#2  (find2digits((pass_cout(pass_cin h cin) cout)))) 

    in 
    if (d1<>d2) then 
    (d1::[],[]) 
    else ([],[]) 
    end 
|action (cin,cout,first::t) = 
    let 
    val s1 = pass_cout ((pass_cin first cin) cout) 
    val s2 = pass_cout (last_element t) cout (**) 
    val d1 = #1 find2digits(s2) 
    val d2 = #2 find2digits(s2) 
    val neo_in = produce_cin s1 s2 (**) 
    val neo_out = produce_cout s2 

    in 
    if (neo_in<2 andalso neo_out<2) then 
    (d1::action(neo_in,neo_out,cut (first::t)),d2::action(neo_in,neo_out,cut (first::t))) (**) 
    else ([],[]) 
    end; 
+0

Ваш код содержит несколько ссылок на функции, которые не определены (например, '' find2digits' и pass_cout'), так что трудно сказать что-либо значимое, тем более, что ваши намерения кажутся неясными. Что ты пытаешься сделать? Я скажу это, хотя - когда у вас есть несколько связок 'val' внутри' let', они должны быть разделены точками с запятой, а не с символами новой строки. –

+3

@JohnColeman: точки с запятой между объявлениями являются необязательными, а также внутри let-bindings. Несколько связанный оператор с запятой между выражениями (единственные действительно полезные точки с запятой в SML) требует скобок вокруг них, например. '(f x; ...; g y)' кроме внутренних let-bindings: 'let ... in f x; ...; g y end'. Это делается для того, чтобы устранить его с помощью менее полезной точки с запятой между декларациями. Поскольку не может быть декларации непосредственно внутри 'let ... in' и' end' (если не введена внутренняя let-binding), скобки могут быть опущены там. –

+0

@SimonShine Вы, конечно, правы. Я знал это, но временно забыл об этом. Я проверил в Ульмане, но он один из тех авторов, который часто использует точки с запятой. –

ответ

2

Я вижу, что вы задаете три вопроса.

Могу ли я использовать несколько объявлений val в let?

Да. Вы уже делаете это массово.

Is let/val/in [/ end] б/у в картинке сопоставив?

Я не совсем уверен, что вы имеете в виду, поэтому я постараюсь ответить на все вопросы, которые, я думаю, вы можете просить.

Во-первых, let-bindings Позволяет временно привязать результат вычисления или значения к имени. Это полезно, если вам нужно использовать результат несколько раз, а вычисление стоит дорого или требует побочных эффектов, которые вы не хотите повторять. Но они также могут сделать код более читаемым (поскольку имя может добавить значение). Соответствие шаблону позволяет обрабатывать несколько случаев разных входов в каждом конкретном случае. Вы можете соответствовать произвольной глубине, и компилятор часто сможет определить, отсутствуют ли у вас какие-либо шаблоны.

Так что, если вы просите если LET-привязки используются в соответствии модели, ответ да, по крайней мере в следующих смыслах:

  1. Подобно тому, как позволить связываниям временно связывает вычисление или значение для имени, то же самое происходит, когда у вас есть шаблон переменной в вашем шаблоне. Например.

    let val (a, b, c) = f (x, y) in ... end 
    

    эквивалентно

    (case f (x, y) of 
        (a, b, c) => ...) 
    

    с , б и с являются образцы, которые всегда соответствуют и привязаны к некоторому значению в ....

  2. Вы можете позволить-привязки и случая-в с внутри других выпускаемых креплений или регистра в с, например,

    let val result = 
        (case f (i, j) of 
         SOME (x, y) => let val (a, b, c) = (g x, g y, g (x + y)) 
             in 
              ... 
             end 
         | NONE => ...) 
    in ... end 
    

    , но эти примеры часто могут быть упрощены.

И если вы спрашиваете , если соответствующий шаблон используются в LET-привязок, ответ да, есть на самом деле немного сопоставления с образцом происходит при создании подведенного связывания; например в

let 
    val (s1, d1, d2) = (pass_cout(pass_cin h cin) cout, 
         #2 (find2digits((pass_cout(pass_cin h cin) cout))), 
         #2 (find2digits((pass_cout(pass_cin h cin) cout)))) 
in ... end 

val (s1, d1, d2) = ... связывание использует сопоставление с образцом на 3-кортежа. Совместимость шаблонов в let-bindings составляет только. Хороший выбор при работе с Типы продуктов и никогда с суммы типов. См What are "sums-and-products" data structures? - то есть, никогда не

val SOME x = f x 

, потому что она взорвется момент f x является NONE. Корпус лучше подходит для большего диапазона шаблонов, чем let-in-end, тогда как let-in-end лучше подходит для выполнения последовательного диапазона заданий, например.

fun solve2 (a : real, b : real, c : real) = 
    let val discr = b * b - 4.0*a*c 
     val sqr = Math.sqrt discr 
     val denom = 2.0 * a 
    in ((~b + sqr)/denom, 
     (~b - sqr)/denom) end 

Почему моя программа дает мне «оператор не является функцией» ошибка?

Как говорит Джон, это трудно понять, потому что код, который вы написали будет работать лишь при наличии значимых определений для значений pass_cout, pass_cin, find2digits, last_element, produce_cin и produce_cout. Способ передачи сообщения об ошибке не указывает на то, что кажется проблемой, и код, который вы пишете, не может быть запущен для полного воспроизведения сообщения об ошибке. Если бы у меня были значимые значения для них, кажется, что есть другие проблемы с этим кодом, где типы не объединяются.

Поскольку ваш код не ретранслировать свои собственные намерения (с родовыми именами, как action, s1, d2 и т.д.), я также не могу рекомендовать лучший способ, чтобы написать это, потому что я понятия не имею, что он должен делать, так вот некоторые общие рекомендации по стилю кодирования:

  1. Использование LET-привязок, чтобы избежать вызова функций, таких как find2digits дважды, например, подобный

    let 
        val (d1, d2) = find2digits ... 
        val s1 = pass_cout ... 
    in 
        ... 
    end 
    
  2. Разделите свои линии должным образом, например. как

    if neo_in < 2 andalso neo_out < 2 
    then (d1::action(neo_in,neo_out,cut (first::t)), 
         d2::action(neo_in,neo_out,cut (first::t))) 
    else ([],[]) 
    

    и даже лучше, как

    if neo_in < 2 andalso neo_out < 2 
    then let 
         val wat = action (neo_in, neo_out, cut (first::t)) 
        in 
         (d1::wat, d2::wat) 
        end 
    else ([], []) 
    

    где wat заменяется какой-то значимое имя, описывающее, что это такое.

  3. Choose good variable names!

+0

Спасибо за помощь. Мои функции pass_cin и pass_cout принимают 2 целых числа в качестве входных данных и производят 1 целое число в качестве вывода. Так вы понимаете, почему возникает ошибка в s1? – iwia

+0

@iwia: Я могу вывести типы этих функций, так что это не мое беспокойство. Вам действительно нужно сосредоточиться на том, чтобы сделать исходный код понятным как часть материала для чтения. Прочтите, например, [это руководство по лучшей практике для создания кода более читаемым] (http://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118) , (Примеры не в ML, но они должны быть достаточно общими, чтобы учиться в любом случае.) –

 Смежные вопросы

  • Нет связанных вопросов^_^