“интервал-> интервал-> интервал”, Что это означает в F#?

Интересно, что это означает в F#.
“функция, берущая целое число,
который возвращает функцию, которая берет целое число и возвращает целое число”.

Но я не понимаю это хорошо.
Кто-либо может объяснить это, так очиститесь?

[Обновление]:

> let f1 x y = x+y ;;

 val f1 : int -> int -> int

Что это означает?

14
задан Tad Donaghe 1 February 2010 в 20:04
поделиться

11 ответов

Типы F #

Начнем с начала.

F # использует нотацию двоеточия (: ) для обозначения типов вещей. Допустим, вы определяете значение типа int :

let myNumber = 5

F # Interactive поймет, что myNumber является целым числом, и сообщит вам это с помощью:

myNumber : int

, которое читается как

myNumber относится к типу int

Функциональные типы F #

Пока все хорошо. Давайте введем кое-что еще, функциональные типы . Функциональный тип - это просто тип функции . F # использует -> для обозначения функционального типа. Эта стрелка символизирует, что то, что написано на ее левой стороне, преобразуется в то, что написано на ее правой стороне.

Давайте рассмотрим простую функцию, которая принимает один аргумент и преобразует его в один вывод. Примером такой функции может быть:

isEven : int -> bool

Здесь вводится имя функции (слева от : ) и ее тип. Эту строку на английском языке можно прочитать как:

isEven относится к типу функции, которая преобразует int в bool .

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

В F # функции - это значения

В F # функции (почти) не более специальные, чем обычные типы. Это вещи, которые вы можете передавать функциям, возвращать из функций, точно так же, как bools, int или strings.

Итак, если у вас есть:

myNumber : int
isEven : int -> bool

, вы должны рассматривать int и int -> bool как две сущности одного типа: типы. Здесь myNumber - это значение типа int , а isEven - это значение типа int -> bool (это то, что я Я пытаюсь символизировать, когда говорю о короткой паузе выше).

Приложение функции

Значения типов, которые содержат -> , также называются функциями и имеют особые полномочия: вы можете применить функцию к значению. Так, например,

isEven myNumber

означает, что вы применяете функцию с именем isEven к значению myNumber . Как и следовало ожидать, проверив тип isEven , он вернет логическое значение. Если вы правильно реализовали isEven , он, очевидно, вернет false .

Функция, возвращающая значение функционального типа

Давайте определим универсальную функцию, чтобы определить, является ли целое число кратным некоторому другому целому числу.Мы можем представить, что тип нашей функции будет (круглые скобки здесь, чтобы помочь вам понять, они могут присутствовать или не присутствовать, они имеют особое значение):

isMultipleOf : int -> (int -> bool)

Как вы можете догадаться, это читается как:

isMultipleOf относится к функции типа (PAUSE), которая преобразует int в функцию (PAUSE), которая преобразует int в bool .

(здесь (ПАУЗА) обозначает паузы при чтении вслух).

Мы определим эту функцию позже. Перед этим давайте посмотрим, как мы можем его использовать:

let isEven = isMultipleOf 2

F # interactive ответит:

isEven : int -> bool

читается как

isEven имеет тип int -> bool

Здесь ] isEven имеет тип int -> bool , поскольку мы только что присвоили значение 2 ( int ) isMultipleOf , что, как мы уже видели видно, преобразует int в int -> bool .

Мы можем рассматривать эту функцию isMultipleOf как своего рода создатель функции .

Определение isMultipleOf

Итак, теперь давайте определим эту мистическую функцию создания функций.

let isMultipleOf n x =
    (x % n) = 0

Легко, а?

Если вы введете это в F # Interactive, он ответит:

isMultipleOf : int -> int -> bool

Где скобки?

Обратите внимание, что скобок нет. Для вас это сейчас не особенно важно. Просто помните, что стрелки правоассоциативны . То есть, если у вас есть

a -> b -> c

, вы должны интерпретировать его как

a -> (b -> c)

Правое в правоассоциативное означает, что вы должны интерпретировать, как если бы были круглые скобки вокруг крайнего правого оператора.Итак:

a -> b -> c -> d

следует интерпретировать как

a -> (b -> (c -> d))

Использование isMultipleOf

Итак, как вы видели, мы можем использовать isMultipleOf для создания новых функций:

let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10

F # Interactive ответит :

isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool

Но можно использовать по-другому. Если вы не хотите (или вам нужно)создать новую функцию, вы можете использовать ее следующим образом:

isMultipleOf 10 150

Это вернет true , поскольку 150 кратно 10. Это точно так же, как создание функции endWithZero и затем применяя его к значению 150.

Фактически, приложение функции остается ассоциативным , что означает, что строку выше следует интерпретировать как:

(isMultipleOf 10) 150

То есть вы помещаете скобку вокруг самой левой функции заявление.

Теперь, если вы понимаете все это, ваш пример (которым является канонический CreateAdder ) должен быть тривиальным!

Некоторое время назад кто-то задал этот вопрос , который касается точно такой же концепции, но в Javascript. В своем ответе я привожу два канонических примера (CreateAdder, CreateMultiplier) в Javascript, которые несколько более четко относятся к возвращаемым функциям.

Надеюсь, это поможет.

57
ответ дан 1 December 2019 в 05:49
поделиться

Концепция называется Функция высшего порядка и является достаточно общей для функционального программирования.

Сами по себе функции - это всего лишь другой тип данных. Поэтому можно записывать функции, которые возвращают другие функции. Конечно, можно иметь функцию, которая принимает int в качестве параметра и возвращает что-то другое. Объедините их и рассмотрим следующий пример (на питоне):

def mult_by(a):
    def _mult_by(x):
        return x*a
    return mult_by

mult_by_3 = mult_by(3)

print mylt_by_3(3)
9

(извините за использование питона, но я не знаю f#)

.
0
ответ дан 1 December 2019 в 05:49
поделиться

Каноническим примером этого, вероятно, является "создатель сумматора" - функция, которая, учитывая число (например, 3), возвращает другую функцию, которая принимает целое число и добавляет к нему первое число.

Так, например, в псевдокоде

x = CreateAdder(3)
x(5) // returns 8
x(10) // returns 13
CreateAdder(20)(30) // returns 50

я недостаточно хорошо знаком с F #, чтобы пытаться написать его, не проверяя его, но C # будет примерно таким:

public static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}

Это поможет?

] РЕДАКТИРОВАТЬ: Как заметил Бруно, пример, который вы указали в своем вопросе, - это именно тот пример, для которого я привел код C #, поэтому приведенный выше псевдокод будет выглядеть следующим образом:

let x = f1 3
x 5 // Result: 8
x 10 // Result: 13
f1 20 30 // Result: 50
9
ответ дан 1 December 2019 в 05:49
поделиться

Это функция, которая принимает целое число и возвращает функцию, которая принимает целое число и возвращает целое.

Эта функция функционально эквивалентна функции, которая берет два целых числа и возвращает целое. Такой способ обращения с функциями, которые берут множественные параметры, распространен в функциональных языках и позволяет легко частично применить функцию к значению.

Например, предположим, что существует функция сложения, которая берет два целых числа и складывает их вместе:

let add x y = x + y

У вас есть список, и вы хотите добавить 10 к каждому элементу. Вы частично применяете функцию add к значению 10. Она привяжет один из параметров к 10 и оставит другой аргумент несвязанным.

let list = [1;2;3;4]
let listPlusTen = List.map (add 10)

Этот трюк делает составление функций очень простым и делает их очень многоразовыми. Как видите, вам не нужно писать другую функцию, которая добавляет 10 к элементам списка, чтобы передать его на карту . Вы только что повторно использовали функцию add.

7
ответ дан 1 December 2019 в 05:49
поделиться

Обычно вы интерпретируйте это как функцию, которая принимает два целых числа и возвращает целое число. Вы должны прочитать о каррировании .

6
ответ дан 1 December 2019 в 05:49
поделиться

функция, принимающая целое число, которая возвращает функцию, которая принимает целое число и возвращает целое число

Последняя часть:

функция, которая принимает целое число и возвращает целое число

должна быть довольно простой, C# пример:

public int Test(int takesAnInteger) { return 0; }

Итак, осталось

функция, принимающая целое число, которая возвращает (функция, подобная приведенной выше)

C# опять:

public int Test(int takesAnInteger) { return 0; }
public int Test2(int takesAnInteger) { return 1; }

public Func<int,int> Test(int takesAnInteger) {
    if(takesAnInteger == 0) {
        return Test;
    } else {
        return Test2;
    }
}
2
ответ дан 1 December 2019 в 05:49
поделиться

Ответ зависит конкретно от того, что вы имеете в виду под записями «top 1000 distinct».

Если вы хотите вернуть не более 1000 отдельных записей, независимо от количества дубликатов в таблице, напишите следующее:

SELECT DISTINCT TOP 1000 id, uname, tel
FROM Users
ORDER BY <sort_columns>

Если вы хотите найти только первые 1000 строк в таблице и потенциально вернуть гораздо меньше 1000 отдельных строк, вы бы написали это с помощью подзапроса или CTE, как это:

SELECT DISTINCT *
FROM
(
    SELECT TOP 1000 id, uname, tel
    FROM Users
    ORDER BY <sort_columns>
) u

Параметр ORDER BY является необязательным, если вас не волнует, какие записи вы вернете.

-121--1308431-

Вы правы, что должны использовать BroadcastReceiver .

Посмотрите на этот вопрос о перезапуске аварийных сигналов при модернизации ; В нем показано, как можно использовать ACTION _ PACKAGE _ REPLACED Намерение при обновлении приложения.

-121--3133458-

В F # (и многих других функциональных языках) существует понятие, называемое curried functions. Это то, что ты видишь. По существу, каждая функция принимает один аргумент и возвращает одно значение.

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

Это отображается в сигнатуре типа. Думайте, что стрелка в сигнатуре типа означает «берет вещь с левой стороны и возвращает вещь с правой стороны». В типе int - > int - > int это означает, что он принимает аргумент типа int - целое число - и возвращает функцию типа int - > int - функцию, которая принимает целое число и возвращает целое число. Вы заметите, что это точно соответствует описанию того, как любопытные функции работают выше.

1
ответ дан 1 December 2019 в 05:49
поделиться

Пример:

let fba = pown ab // fab = a ^ b

- функция, которая принимает int (показатель степени) и возвращает функцию, которая увеличивает свой аргумент до этой экспоненты, например

let sqr = f 2

или

let tohepowerofthree = f 3

so

sqr 5 = 25

tohepowerofthree 3 = 27

0
ответ дан 1 December 2019 в 05:49
поделиться

Здесь уже есть много ответов, но я хотел бы предложить еще один вариант. . Иногда объяснение одного и того же разными способами помогает вам «ощутить» это.

Мне нравится думать о функциях как «вы даете мне что-то, а я верну вам что-то другое»

Итак, Func говорит: «вы даете мне int , и я дам тебе строку ».

Мне также легче думать в терминах «позже»: « Когда вы дадите мне int, я дам вам строку». Это особенно важно, когда вы видите такие вещи, как myfunc = x => y => x + y (" Когда вы даете карри x, вы получаете то, что когда вы дадите ay вернет x + y ").

(Кстати, я предполагаю, что вы здесь знакомы с C #)

Итак, мы могли бы выразить ваш пример int -> int -> int как Func > .

Другой способ, которым я смотрю на int -> int -> int , заключается в том, что вы удаляете каждый элемент слева, предоставляя аргумент соответствующего типа. А когда у вас больше нет -> , у вас заканчивается «позднее», и вы получаете значение.


(Просто для удовольствия) вы можете преобразовать функцию, которая принимает все аргументы за один раз, в функцию, которая принимает их «постепенно» (официальный термин для их постепенного применения - «частичное применение»), это называется «каррирование» ':

static void Main()
{
    //define a simple add function
    Func<int, int, int> add = (a, b) => a + b;

    //curry so we can apply one parameter at a time
    var curried = Curry(add);    

    //'build' an incrementer out of our add function
    var inc = curried(1);         // (var inc = Curry(add)(1) works here too)
    Console.WriteLine(inc(5));    // returns 6
    Console.ReadKey();
}
static Func<T, Func<T, T>> Curry<T>(Func<T, T, T> f)
{
    return a => b => f(a, b);
}
0
ответ дан 1 December 2019 в 05:49
поделиться

Вот мои 2 c. По умолчанию функции F# позволяют частичное применение или currying. Это означает, что когда вы определяете это:

let adder a b = a + b;;

Вы определяете функцию, которая принимает целое число и возвращает функцию, которая принимает целое число и возвращает целое число или int -> int -> int. Керринг позволяет частично применить функцию для создания другой функции:

let twoadder = adder 2;;
//val it: int -> int

В приведенном выше коде a предопределено до 2, так что всякий раз, когда вы вызываете twoadder 3, он просто добавляет два к аргументу.

Синтаксис, в котором параметры функции разделяются пробелом, эквивалентен этому синтаксису лямбды:

let adder = fun a -> fun b -> a + b;;

Что является более читабельным способом понять, что две функции на самом деле соединены в цепочку.

0
ответ дан 1 December 2019 в 05:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: