Это означает, что lp
- это функция, которая принимает 2 параметра, первый из которых curr
, а второй, ну, список, который по логике может быть либо пустым ([]
), либо содержать хотя бы один элемент ((a::l)
- шаблон для списка, где a
находится во главе, а остальная часть списка - l
).
Если перевести этот фрагмент кода FP на известный императивный язык, это будет выглядеть так:
function lp(curr, lst) {
if (lst.length == 0) {
return curr;
} else {
var a = lst[0]; // first element
var l = lst.slice(1, lst.length); // the rest
if (gt(a, curr)) {
return lp(a, l);
} else {
return lp(curr, l)
}
}
}
Довольно громоздко, но это точный перевод.
Функциональные языки основаны на лямбда-исчислении, где функции принимают ровно одно значение и возвращают один результат. Хотя SML и другие языки FP основаны на этой теории, на практике это довольно неудобно, поэтому многие из этих языков позволяют выражать передачу нескольких параметров функции через так называемый Currying.
Итак, да, в ML функции фактически принимают только одно значение, но каррирование позволяет имитировать несколько аргументов.
Давайте создадим функцию с именем add
, которая складывает 2 числа:
fun add a b = a + b
должен это сделать, но мы определили 2 параметра. Какой тип add
? Если вы посмотрите в REPL, это val add = fn : int -> int -> int
. Что гласит: "add - это функция, которая принимает int и возвращает другую функцию (которая принимает int и возвращает int)"
Таким образом, мы могли бы определить add
так:
fun add a =
fn b => a + b
И вы увидите, что они похожи. Фактически, можно с уверенностью сказать, что в некотором смысле первое является синтаксическим сахаром для более позднего. Таким образом, все функции, которые вы определяете в ML, даже с несколькими аргументами, на самом деле являются функциями с одним аргументом, которые возвращают функции, которые принимают второй аргумент, и так далее. Сначала к этому немного сложно привыкнуть, но очень скоро это становится второй натурой.
fun add a b = a + b (* add is of type int -> int -> int *)
add 1 2 (* returns 3 as you expect *)
(* calling add with only one parameter *)
val add1 = add 1
Что add1
? Это функция, которая добавит 1
к единственному аргументу, который вы ей передаете!
add1 2 (* returns 3 *)
Это пример частичного приложения, где вы вызываете функцию по частям, по одному аргументу за раз, каждый раз возвращаясь, другая функция принимает остальные аргументы.
Кроме того, есть еще один способ создать несколько аргументов: кортежи:
(1, 2); (* evaluates to a tuple of (int,int) *)
fun add (a,b) = a + b;
add (1, 2) (* passing a SINGLE argument to a function that
expects only a single argument, a tuple of 2 numbers *)
В вашем вопросе lp
мог также быть реализован как lp (curr, someList)
:
fun max gt curr lst =
let fun lp (curr, []) = curr
| lp (curr, (a::l)) = if gt(a,curr) then lp (a, l)
else lp (curr, l)
in
lp (curr, lst)
end
Обратите внимание, что в этом случае мы должны объявить max
как max gt curr lst
!
В опубликованном вами коде lp
явно был реализован с каррированием. А сам тип max
был fn: ('a * 'a -> bool) -> 'a -> 'a list -> 'a
. Разобрав это на части:
('a * 'a -> bool) -> (* passed to 'max' as 'gt' *)
'a -> (* passed to 'lp' as 'curr' *)
'a list -> (* passed to 'lp' as 'someList' *)
'a (* what 'lp' returns (same as what 'max' itself returns) *)
Обратите внимание на тип gt
, первый аргумент max
: fn : (('a * 'a) -> bool)
- это функция одного аргумента ('a * 'a)
, кортежа из двух 'a
, и он возвращает 'a
. Так что карри здесь нет.
Что использовать - дело вкуса, условностей и практических соображений.
Надеюсь это поможет.
person
Faiz
schedule
21.01.2013
lp
и что такоеcurr
? Является ли параметр кортежем(curr,someList)
? - person Nosrettap   schedule 21.01.2013