Skip to content

Instantly share code, notes, and snippets.

@asufana
Last active December 14, 2015 03:03
Show Gist options
  • Save asufana/ce155da307f979d444db to your computer and use it in GitHub Desktop.
Save asufana/ce155da307f979d444db to your computer and use it in GitHub Desktop.
F# (FSharp) を LL ぽく勉強してみる

F# (FSharp) を LL ぽく勉強してみる

環境構築

参考:http://fsharp.org/use/mac/

  • Xamarin Studio をインストールすることで、F#のラインタイムもインストールされる

ATOM設定

プラグインインストール

linter
language-fsharp
ionide-fsharp
  • MonoPath に /usr/local/bin を設定

REPLを使ってみる

$ fsharpi
- 1+1;;
val it : int = 2
-
- let list = [1..5]
- printfn "list: %A" list;;
list: [1; 2; 3; 4; 5]

Hello world してみる

$ touch hello.fs
$ vim hello.fs
#!/usr/bin/env fsharpi

printfn "Hello World"

//.netメソッドも使える
//System.Console.WriteLine "Hello World"

$ chmod 777 hello.fs
$ ./hello.fs
Hello world

Haskellと比べてみる

#!/usr/bin/env fsharpi

// 変数束縛
// ・printfn は printf 的な振る舞いをするもの
let list = [1..5]
printfn "list: %A" list

// リスト要素を合計する関数
// ・変数束縛も関数定義も同じletで行う
// ・オフサイドルールが適用されるので、doneやendを省略可能、スコープもオフサイドラインで限定される
let rec sum' list =
  match list with
  | []    -> 0
  | x::xs -> x + sum' xs

// リスト要素を合計する関数を Haskell で定義すると
//  sum' []     = 0
//  sum' (x:xs) = x + sum' xs

// 関数を適用する
list |> sum' |> printfn "sum:  %A"

// パイプライン演算子を利用して、読みやすく
// これと同じ意味 printfn "%A" ( sum' list )
// haskellだと print $ sum' list

// -----------------------------------

// function式:引数が1つのパターンマッチ糖衣構文
let rec sum'' = function
  | []    -> 0
  | x::xs -> x + sum'' xs

// -----------------------------------

// リスト要素を逆順にする関数
// ・リスト最後に要素を追加する演算子はhaskell同様存在しないため、@演算子でリスト結合する
let rec reverse' = function
  | []    -> []
  | x::xs -> (reverse' xs) @ [x]

list |> reverse' |> printfn "rvrs: %A"

// haskellでは
// reverse' []     = []
// reverse' (x:xs) = reverse' xs ++ [x]

// -----------------------------------

// リスト先頭からn個を抽出する関数
// ・複数値引数を取るため、function式では記述できない
// ・また複数値に対してパターンマッチができない?ため、タプル化して引数を1つにしてマッチする
let rec take' n list =
  match (n,list) with
  | (n,_) when n < 1 -> []
  | (_,[])           -> []
  | (n,x::xs)        -> x :: take' (n - 1) xs

list |> take' 2 |> printfn "take: %A"

// haskellでは
// take' _ []        = []
// take' n _ | n < 1 = []
// take' n (x:xs)    = x : take' (n - 1) xs
// F#ではガードはwhenで記述する

// でもこんな書き方でもOK
let rec take'' n list =
  match list with
  | _ when n < 1 -> []
  | []           -> []
  | x::xs        -> x :: take'' (n - 1) xs

// -----------------------------------

// FizzBuzz
// ・再帰処理がない場合には、キーワード rec が不要
let fizzbuzz = function
  | n when n % 15 = 0 -> "FizzBuzz"
  | n when n %  5 = 0 -> "Buzz"
  | n when n %  3 = 0 -> "Fizz"
  | n                 -> n |> string

// リストの各要素に適用したいので、map関数を利用する
list |> List.map fizzbuzz |> printfn "fizz: %A"

// haskellでは
// fizzbuzz n
//  | n `mod` 15 == 0 = "FizzBuzz"
//  | n `mod`  5 == 0 = "Buzz"
//  | n `mod`  3 == 0 = "Fizz"
//  | otherwise       = show n

// -----------------------------------

// Fibonacci
let rec fib = function
  | n when n < 0 -> 0
  | n when n < 2 -> n
  | n -> fib(n - 2) + fib(n - 1)

fib 6 |> printfn "fibo: %A"

// haskellでは
//fib 0 = 0
//fib 1 = 1
//fib n | n > 1 = fib (n - 2) + fib (n - 1)

// -----------------------------------

// Listモジュール
List.length list |> printfn "leng: %A"
List.isEmpty list |> printfn "empt: %A"
List.rev list |> printfn "rev:  %A"

// funキーワードでラムダ式を記述
// let twice x = x * x と同じ
let twice = fun x -> x * x
List.map twice list |> printfn "twce:  %A"

//畳み込み
List.reduce (+) list |> printfn "rdce:  %A"

// 初期値を取るreduce
List.fold (+) 1 list |> printfn "fold:  %A"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment