急にF#が書きたくなったのでよく見かける言語処理100本ノックをやりました.
始めて3日ほどなので良い書き方を教えていただきたいです.
問題はこちらです.
http://www.cl.ecei.tohoku.ac.jp/nlp100/
今回は手軽に書いて実行できるF# Interactiveを使いました.
環境
- .NET Core v3.0.0-preview6
- F# 4.6
本題
00. 文字列の逆順
let stringReverse (str : string) =
str
|> Seq.rev
|> Seq.map string
|> String.concat ""
stringReverse "stressed" |> printfn "%s"
// desserts
01. 「パタトクカシーー」
let getOddIndices (str : string) =
seq {
for i in 0..str.Length - 1 do
if i % 2 = 1 then yield str.[i]
}
|> Seq.map string
|> String.concat ""
getOddIndices "パタトクカシーー" |> printfn "%s"
// タクシー
02. 「パトカー」+「タクシー」=「パタトクカシーー」
let stringConcat (str1 : string) (str2 : string) =
let minLength = Array.min [| str1.Length; str2.Length |]
seq {
for i in 0..minLength - 1 -> string str1.[i] + string str2.[i]
}
|> Seq.reduce (+)
stringConcat "パトカー" "タクシー" |> printfn "%s"
// パタトクカシーー
03. 円周率
let decomposeAndCount (str : string) = str.Split(' ') |> Seq.map String.length
"Now I need a drink, alcoholic of course, after the heavy lectures involving \
quantum mechanics."
|> decomposeAndCount
|> printfn "%A"
// seq [3; 1; 4; 1; ...]
04. 元素記号
let genElemMap (l : int []) (str : string) =
let s = str.Split(' ')
seq {
for i in 1..s.Length do
if Seq.contains i l then yield string s.[i - 1].[0]
else yield s.[i - 1].[0..1]
}
|> Seq.zip (seq {
for i in 1..s.Length -> i
})
|> Map.ofSeq
let singleList = [| 1; 5; 6; 7; 8; 9; 15; 16; 19 |]
"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also \
Sign Peace Security Clause. Arthur King Can."
|> genElemMap singleList
|> printfn "%A"
// map
// [(1, "H"); (2, "He"); (3, "Li"); (4, "Be"); (5, "B"); (6, "C"); (7, "N"); (8, "O"); (9, "F"); ...]
05. n-gram
task5.fsx
let makeNGram (n : int) (sequence : seq<_>) =
let s = Seq.toList sequence
seq {
for i in 0..s.Length - n -> s.[i..i + n - 1]
}
// word n-gram
"I am an NLPer".Split(' ')
|> makeNGram 2
|> printfn "%A"
// string n-gram
"I am an NLPer"
|> makeNGram 2
|> printfn "%A"
// seq [["I"; "am"]; ["am"; "an"]; ["an"; "NLPer"]]
// seq [['I'; ' ']; [' '; 'a']; ['a'; 'm']; ['m'; ' ']; ...]
06. 集合
上で作ったmakeNGram
を利用しています.
F# Interactiveでは #load "hoge.fsx"
として別ファイルを読み込んで実行できるのですが, 関数のみを読み込んだり, 或いはPythonのif __name__ == '__main__':
のように呼び出された時は実行しないオプションみたいなのはあるのでしょうか...
#load "./task5.fsx"
open Microsoft.FSharp.Collections
open Task5
let x =
"paraparaparadise"
|> makeNGram 2
|> set
let y =
"paragraph"
|> makeNGram 2
|> set
let except x y = x - Set.intersect x y
Set.union x y |> printfn "Union: %A"
except x y |> printfn "Except: %A"
Set.intersect x y |> printfn "Intersect: %A"
// Union: set [['a'; 'd']; ['a'; 'g']; ['a'; 'p']; ['a'; 'r']; ['d'; 'i']; ['g'; 'r']; ['i'; 's']; ['p'; 'a']; ['p'; 'h']; ...]
// Except: set [['a'; 'd']; ['d'; 'i']; ['i'; 's']; ['s'; 'e']]
// Intersect: set [['a'; 'p']; ['a'; 'r']; ['p'; 'a']; ['r'; 'a']]
07. テンプレートによる文生成
let generateTemplate x y z = string x + "時の" + string y + "は" + string z
generateTemplate 12 "気温" 22.4 |> printfn "%s"
// 12時の気温は22.4
08. 暗号文
open System
let reverseLowerCase c = 219 - int c |> char
let cipher str =
str
|> Seq.map (function
| c when Char.IsLower c -> reverseLowerCase c
| c -> c
>> string)
|> Seq.reduce (+)
"Hello F#!"
|> cipher
|> printfn "%s"
// Hvool F#!
09. Typoglycemia
open System
let permuteWord str =
match String.length str with
| n when n <= 4 -> str
| n ->
let rnd = Random()
let middle =
str.[1..n - 2]
|> Seq.sortBy (fun _ -> rnd.Next())
|> Seq.map string
|> Seq.reduce (+)
string str.[0] + middle + string str.[n - 1]
let typoglycemia (str : string) =
str.Split(' ')
|> Seq.map permuteWord
|> String.concat " "
"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
|> typoglycemia
|> printfn "%s"
// I cun'odlt believe that I cluod altulcay utnaesrdnd what I was ranideg : the paennoehml power of the huamn mind .