Почему я использую `let`, а не просто` val` для объявления переменной внутри функции в SML? - PullRequest
0 голосов
/ 04 мая 2018

В SML меня научили идиоматическому способу определения локальной переменной для функции как:

fun correct_fun() =
    let val x = 1
    in x + 2
    end

Почему я должен использовать let, а не просто val, вот так:

fun incorrect_fun() =
    val x = 1
    x + 2

incorrect_fun() выдает ошибку, но я не понимаю, почему. Почему нельзя использовать val внутри функции без let?

1 Ответ

0 голосов
/ 04 мая 2018

Почему нельзя val использовать внутри функции без let?

Поскольку val является своего рода объявлением, let является разновидностью выражения, а тело функции является выражением.

Синтаксическая структура let -экспрессии: letdecinexpend. Таким образом, при использовании let -выражения в качестве тела функции exp в пределах let эквивалентно телу функции, но с расширенной локальной областью независимо от того, dec добавляет.

Выражение let позволяет использовать любые объявления, а не только val объявления.

Например, вы можете использовать обработку исключений в качестве механизма потока управления, используемого для обратного отслеживания, и вы можете вкладывать вспомогательные функции, которые используются только локально и, возможно, принимают несколько аргументов для хранения временного результата, но вы можете не захотеть выставлять исключение или вспомогательные функции. Так что для головоломки Восемь королев вы можете уточнить это решение (из дополнительных примечаний по функциональному программированию, с. 140-143 , Нильс Андерсен):

fun concatMap f xs = String.concat (List.map f xs)
fun concatTab f n = String.concat (List.tabulate (n, f))

fun dots n = concatTab (fn _ => ". ") n
fun show ys = concatMap (fn y => dots (y - 1) ^ "* " ^ dots (8 - y) ^ "\n") ys

fun queen dims =
    let exception Queen
        fun beats ((x,y),(x1,y1)) = (* x = x1 *)
                         (* orelse *)  y = y1
                            orelse x + y = x1 + y1
                            orelse x - y = x1 - y1

        fun safe ((x, y), _, []) = true
          | safe ((x, y), x1, y1::ys) =
            not (beats ((x, y), (x1, y1))) andalso safe ((x, y), x1 + 1, ys)

        fun queen' ((0, _), ys) = ys
          | queen' ((_, 0), _) = raise Queen
          | queen' ((x, y), ys)  =
            if safe ((x, y), x + 1, ys)
              then queen' ((x - 1, 8), y :: ys)
                   handle Queen => queen' ((x, y - 1), ys)
              else queen' ((x, y - 1), ys)

    in queen' (dims, []) end

Демонстрация этого;

- print (show (queen ((8,8))));
. . . . * . . . 
. . . . . . * . 
. * . . . . . . 
. . . . . * . . 
. . * . . . . . 
* . . . . . . . 
. . . * . . . . 
. . . . . . . * 

Когда вы используете let -выражения в основном для объявления временных значений, вы также можете рассмотреть возможность использования case-of. См. Вопросы и ответы по Разница между "local" и "let" в вложенных локальных объявлениях SML и в ML для NJ .

...