Ответ 1
Не проклинать себя ужасно, но я написал пару обзорных сообщений F # в своем блоге здесь и . Крис Смит (парень в команде F # в MS) имеет статью под названием "F # за 20 минут" - часть 1 и часть 2.
Обратите внимание, что вы должны быть осторожны, поскольку последний CTP F # (версия 1.9.6.0) имеет некоторые серьезные нарушения в сравнении с предыдущими версиями, поэтому некоторые примеры/учебные пособия там могут не работать без изменений.
Здесь быстрый прорыв какой-нибудь классной вещи, может быть, я могу дать вам несколько намеков здесь, которые явно очень короткие и, вероятно, не велики, но, надеюсь, вам что-то поиграть!: -
Первое примечание - большинство примеров в Интернете предполагают, что "легкий синтаксис" включен. Для этого используйте следующую строку кода: -
#light
Это не позволяет вам вставлять определенные ключевые слова, присутствующие в совместимости с OCaml, а также прерывать каждую строку с точкой с запятой. Обратите внимание, что использование этого синтаксиса означает, что отступ определяет область. Это станет понятным в более поздних примерах, все из которых полагаются на легкий синтаксис.
Если вы используете интерактивный режим, вам нужно завершить все инструкции с помощью двух полуколонок, например: -
> #light;;
> let f x y = x + y;;
val f : int -> int -> int
> f 1 2;;
val it : int = 3
Обратите внимание, что интерактивный режим возвращает результат "val" после каждой строки. Это дает важную информацию о определениях, которые мы делаем, например, "val f: int → int → int" указывает, что функция, которая принимает два ints, возвращает int.
Обратите внимание, что только в интерактивном режиме нам нужно прервать линии с полуколонами, когда на самом деле определяем код F #, мы свободны от этого: -)
Вы определяете функции, используя ключевое слово 'let'. Это, вероятно, самое важное ключевое слово во всех F #, и вы будете использовать его много. Например: -
let sumStuff x y = x + y
let sumStuffTuple (x, y) = x + y
Таким образом, мы можем назвать эти функции: -
sumStuff 1 2
3
sumStuffTuple (1, 2)
3
Обратите внимание, что здесь есть два разных способа определения функций: вы можете либо разделять параметры по пробелам, либо указывать параметры в "кортежах" (т.е. значения в круглых скобках, разделенных запятыми). Разница в том, что мы можем использовать "приложение с частичными функциями" для получения функций, которые принимают меньше требуемых параметров с использованием первого подхода, а не второго. Например: -.
let sumStuff1 = sumStuff 1
sumStuff 2
3
Заметим, что мы получаем функцию из выражения "sumStuff 1". Когда мы можем передавать функции так же легко, как и данные, которые называются языком, имеющим "функции первого класса", это фундаментальная часть любого функционального языка, такого как F #.
Совпадение шаблонов довольно чертовски круто, оно в основном похоже на инструкцию switch на стероидах (да, я пометил эту фразу от другого F # -ist:-). Вы можете делать такие вещи, как: -
let someThing x =
match x with
| 0 -> "zero"
| 1 -> "one"
| 2 -> "two"
| x when x < 0 -> "negative = " + x.ToString()
| _ when x%2 = 0 -> "greater than two but even"
| _ -> "greater than two but odd"
Обратите внимание, что мы используем символ "_", когда хотим что-то сопоставить, но возвращаемое выражение не зависит от ввода.
Мы можем сокращать сопоставление образцов, используя инструкции if, elif и else, если требуется: -
let negEvenOdd x = if x < 0 then "neg" elif x % 2 = 0 then "even" else "odd"
Списки F # (которые реализованы как связанные списки внизу) можно манипулировать таким образом: -
let l1 = [1;2;3]
l1.[0]
1
let l2 = [1 .. 10]
List.length l2
10
let squares = [for i in 1..10 -> i * i]
squares
[1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
let square x = x * x;;
let squares2 = List.map square [1..10]
squares2
[1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
let evenSquares = List.filter (fun x -> x % 2 = 0) squares
evenSqares
[4; 16; 36; 64; 100]
Обратите внимание: функция List.map "отображает" квадратную функцию в список от 1 до 10, т.е. применяет функцию к каждому элементу. List.filter 'фильтрует' список, возвращая только значения в списке, которые передают предикат. Также обратите внимание на синтаксис "fun x → f" - это F # lambda.
Обратите внимание, что во всех случаях мы не определили какие-либо типы - типы F-компилятора/интерпретатора F #, то есть выработали то, что вы хотите использовать. Например: -
let f x = "hi " + x
Здесь компилятор/интерпретатор определит, что x является строкой, поскольку вы выполняете операцию, для которой x является строкой. Он также определяет, что тип возврата будет также строкой.
Если существует двусмысленность, компилятор делает предположения, например: -
let f x y = x + y
Здесь x и y могут быть несколькими типами, но компилятор по умолчанию имеет значение int. Если вы хотите определить типы, вы можете использовать аннотацию типа: -
let f (x:string) y = x + y
Также обратите внимание, что нам пришлось заключить в круглые скобки строку x: мы часто должны делать это, чтобы отделить части определения функции.
Два действительно полезных и сильно используемых оператора в F # - это операторы прямой и функциональной компоновки труб | > и → соответственно.
Определим | > таким образом: -
let (|>) x f = f x
Обратите внимание, что вы можете определить операторы в F #, это довольно круто: -).
Это позволяет вам писать вещи более четко, например: -
[1..10] |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
Позволит вам получить первые 10 четных квадратов. Это яснее, чем: -
List.filter (fun x -> x % 2 = 0) (List.map (fun x -> x * x) [1..10])
Ну, по крайней мере, я так думаю: -)
Состав функций, определяемый оператором → , определяется следующим образом: -
let (>>) f g x = g(f(x))
т.е. вы пересылаете транзакцию только параметр первой функции остается неуказанным. Это полезно, поскольку вы можете сделать следующее: -
let mapFilter = List.map (fun x -> x * x) >> List.filter (fun x -> x % 2 = 0)
Здесь mapFilter примет список ввода и возвращает список, отфильтрованный, как и раньше. Это сокращенная версия: -
let mapFilter = l |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
Если мы хотим записать рекурсивные функции, мы должны определить функцию как рекурсивную, поместив "rec" после let. Примеры ниже.
Некоторые интересные вещи: -
Факториал
let rec fact x = if x <= 1 then 1 else x * fact (x-1)
n-й номер Фибоначчи
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2)
FizzBuzz
let (/%) x y = x % y = 0
let fb = function
| x when x /% 15 -> "FizzBuzz"
| x when x /% 3 -> "Fizz"
| x when x /% 5 -> "Buzz"
| x -> x.ToString()
[1..100] |> List.map (fb >> printfn "%s")
В любом случае, это очень краткий обзор, надеюсь, это поможет немного!