FsAdventJP

#105 僕の大好きなF#たん

ども、変態 F#er として有名なガブです。
この記事は F# Advent Calendar 2011 の2日目です。

1日目の id:bleis-tift さん、宣言ではゆるくいくと言っていました。
しかし、関数型プログラミングに馴染みの無いオブジェクト指向プログラマに読んで欲しい、素晴らしいエントリを書き上げてくれました!

[F#]業務で使う関数型言語 (F# 編) 〜 レコードで値オブジェクトを簡単に作る - 予定は未定Blog版

このシリーズ、私の必読リストに追加されました!


で、初日が(内容の素晴らしさはともかく)控えめだったので、2日目は自由にやらせていただこうかと。

 どのくらい自由かと言うと、おそらくタイトルから少しばかりは感じていただけているのではないかと思います。


ホント、誰もついてこれなくなるかもしれませんが、心のアクセルはベタ踏みで突っ走ります!(`・ω・´)

はじめに

さて、かっ飛ばす前に、手前味噌ながら自家製のライブラリをご紹介させていただきます。

Gab-km / OAuth-in-FSharp - GitHub

これは、F#製のOAuthライブラリです。
まだちゃんと動かすのが精一杯で、便利に使えるレベルにはないのですが、まぁ頑張りました。
これが動かなかった頃の思い出話だけで1エントリ書けちゃうんですが、またそれは別のときにでも。

ということで、ここで謝辞を。

アドバイザー:APIインターフェイスについてご相談に乗っていただきました。

参考記事:OAuthの仕組みについて勉強させてもらいました。

参考ソース:F#のソースコードのあるべき姿を研究させていただきました。

参考文献:やりたいことのやり方を、何度も紐解かせていただきました。

使い方

このOAuthライブラリはGitHubの方にざっくりとした使い方を載せています。
ここでは、そこからさらに進めて、Twitterのホームタイムラインを取得するコードを書いてみます。
open OAuth.Types
open OAuth.Core.Base
open OAuth.API

let requestTokenResponse consumerInfo =
    OAuth.API.getRequestToken
        <| Requirement (System.Text.Encoding.ASCII,
                        "https://api.twitter.com/oauth/request_token",
                        GET)
        <| consumerInfo
        <| []

let request consumerInfo = requestTokenResponse consumerInfo |> fromParameter

type MaybeBuilder () =
    member self.Bind (x, f) =
        match x with
        | Some y -> f y
        | None -> None 
    member self.Return (x) = Some x

let maybe = MaybeBuilder ()

let accessTokenResponse consumerInfo =
    maybe {
        let reqList = request consumerInfo
        let! requestToken = tryGetValue "oauth_token" reqList
        let! requestSecret = tryGetValue "oauth_token_secret" reqList
        System.Console.WriteLine "Access below URL."
        let authUrl = System.String.Format (
                        "https://api.twitter.com/oauth/authorize?oauth_token={0}&oauth_token_secret={1}",
                        requestToken, requestSecret)
        System.Console.WriteLine authUrl
        System.Console.Write "Input your pin code. > "
        let pinCode = System.Console.ReadLine ()
        return OAuth.API.getAccessToken
                <| Requirement (System.Text.Encoding.ASCII,
                                "https://api.twitter.com/oauth/access_token",
                                GET)
                <| consumerInfo
                <| { requestToken=requestToken; requestSecret=requestSecret }
                <| pinCode
                <| []
    }

let getAccess consumerInfo =
    match accessTokenResponse consumerInfo with
    | Some response ->  Some (fromParameter response)
    | None -> None

let getTimeline consumerInfo =
     maybe {
        let! accList = getAccess consumerInfo
        let! accessToken = tryGetValue "oauth_token" accList
        let! accessSecret = tryGetValue "oauth_token_secret" accList
        return OAuth.API.useWebService
                <| Requirement (System.Text.Encoding.ASCII,
                                "https://api.twitter.com/1/statuses/home_timeline.xml",
                                OAuth.Types.GET)
                <| consumerInfo
                <| { accessToken=accessToken; accessSecret=accessSecret }
                <| []
    }

[<EntryPoint>]
let main args =
    let consumerInfo = { consumerKey="abcdefghijklmnopqrstuv";
                     consumerSecret="wxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZab" }
    let timeline = getTimeline consumerInfo
    System.Console.WriteLine timeline
    System.Console.Read ()
MaybeBuilderというクラスは、いわゆるMaybeモナドを実現するためのコンピュテーションビルダーです。
今回役に立つのはtryGetValueのところだけなので、あまり意味はありませんね…。
それよか、APIが例外を返したときに以降の処理を安全にキャンセルする、Eitherのような仕組みの方が便利かなと思います。

なお、XML形式のデータが取得できていれば正しく動いています。

F#たん

ところで、皆さんはF#たんをご存知ですか?

F# たん CG - ++C++; // 未確認飛行 C ブログ
F#たん(魔法バージョン) - ++C++; // 未確認飛行 C ブログ
げんごー - pixiv

素晴らしいですね。
ちなみに最初のリンクの画像は、私のThinkPadの壁紙になっています。

僕のF#たん

こんなにステキなF#たんは俺の嫁な訳ですが、姉妹品みたいな感じでC#たんがTwitterにアカウントを持って活動しています。

@csharp_tan - Twitter

他のC++たんとVBたん、F#たんには、まだTwitterアカウントがありません。
(VBたんと思しきscreen_nameはありますが、全く無関係な方のアカウントのようです)
そもそも『C#たんと学ぶ わりと硬派なソフトウェア開発講座』に、F#たんは登場したことs(ry

まぁ無かったら作ってしまえばいいですよね。

@fsharp_tan - Twitter

※画像については、F#たん紹介リンク1番目にて挙げました、岩永さんのサイトより拝借させていただいております。
権利等で問題があるようでしたら、ご指摘いただけましたら削除いたします。


アカウントを作るのなんて、screen_nameが被らなければ造作もありません。
ツイートも、そのアカウントにログインしてWebからできます。

でも、それじゃ面白くない。
F#を使ってツイートしてみようじゃないですか。
open OAuth.Types
open OAuth.Core.Base

let Tweet consumerInfo accessInfo tweet =
    let requirement = Requirement (System.Text.Encoding.UTF8,
                        "http://api.twitter.com/1/statuses/update.xml",
                        OAuth.Types.POST)
    try
        OAuth.API.useWebService requirement consumerInfo accessInfo [KeyValue ("status", tweet)]
    with
    | ex -> System.Console.WriteLine ex
            ""

[<EntryPoint>]
let main args =
    let consumerInfo = { consumerKey="abcdefghijklmnopqrstuv";
                     consumerSecret="wxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZab" }
    let accessInfo = { accessToken="cdefghijklmnopqrstuvwxuz0123456789ABCDEFGHIJKLMNOP"
                        accessSecret="QRSTUVWXYZabcdefghijklmnopqrstuvwxyz123" }
    let response = Tweet consumerInfo accessInfo "そんなにリニアモーターカーに乗りたければ都営大江戸線にでも乗ればいいわ"
    System.Console.WriteLine response
    System.Console.Read ()
これで、このようにツイートされています。

2011/12/01 01:17:15
そんなにリニアモーターカーに乗りたければ都営大江戸線にでも乗ればいいわ

…あぁ、もっと冷たくして…。

僕の大好きなF#たん

と言うわけで、F# Advent Calendar 2011の2日目は、とある変態F#erがTwitterの力を借りて、自分の嫁をF#で喋らせたというお話でした。
最後まで読んでしまって、言葉にならない後悔をした皆さん、3日目以降のカレンダーにご期待ください。

3日目は @linerlock さんです。
えっふしゃーぷ!えっふしゃーぷ!

最後に

F#たんは僕の嫁やで!!

#78 アルゴリズムたいそう!

この記事は F# Advent Calendar jp: 20101315回目です。

F#の事について書こうと思い、そういえば私のブログで一番取り上げてきたトピックは何だろうと振り返ってみました。
そこで浮かんできたのが、次の2点でした。
・アルゴリズムの実装
・処理時間の性能評価

書くならやっぱり自分の書きやすいものだろうと言うことで、今回は
F#でソートアルゴリズムを実装し、処理時間を測定してみる
ことにします(`・ω・´)

なお処理時間の測定には、これまで実績のある以下のコードを利用します。
open System
let beginTime = DateTime.Now;;
let result = "hoge";;  (* ここに処理を書きます *)
let ts = DateTime.Now.Subtract(beginTime);;
printfn "経過時間:%A[ms]" ts.TotalMilliseconds;;

また、統一した仕様としては、int listへの昇順整列操作であることとして、測定には以下のリストを使用します。
let lsSmall = [1;3;5;7;9;2;4;6;8];;
let lsMidAndDup = [10;3;14;13;5;1;11;9;2;5;15;10;4;12;6;8;16;7];;
let rm = new Random(DateTime.Now.Millisecond);;
let lsLarge = List.init 1000 (fun x -> rm.Next());;
let lsLarger = List.init 10000 (fun x -> rm.Next());;
let lsLargest = List.init 100000 (fun x -> rm.Next());;



1. バブルソート


今から20年前に日本で流行った整列アルゴリズム、ではありません。
(く、くるしい!?)

バブルソート - Wikipedia
(以下、横着をして書くソートの説明はWikipediaにお任せしますw)

これをF#で次のように書いてみました。
let bubblesort (ls: int list) =
    let rec countBS lis rest =
        let rec innerBubbleSort lst =
            match lst with
            | x::xs ->
                match xs with
                | y::ys ->
                    if x > y
                        then [y] @ (innerBubbleSort ([x] @ ys))
                        else [x] @ (innerBubbleSort xs)
                | [] -> lst
            | [] -> lst
        in
        if rest > 0
            then countBS (innerBubbleSort lis) (rest-1)
            else lis
    in
    countBS ls (ls.Length-1);;
とりあえず、動きを見てみましょう。
> let ls = lsSmall;;

val ls = [1; 3; 5; 7; 9; 2; 4; 6; 8]

> let beginTime = DateTime.Now;;

val beginTime :  = 2010/12/20 16:14:50

> let bubbleSorted = bubblesort ls;;

val bubbleSorted : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]

> let ts = DateTime.Now.Subtract(beginTime);;

val ts : TimeSpan = 00:00:00.0468750

> printfn "経過時間:%A[ms]" ts.TotalMilliseconds;;
経過時間:46.875[ms]
val it : unit = ()
>
まぁ、こんなものでしょうか。



2. 選択ソート


選択ソート - Wikipedia

2番目は選択ソートです。
以下のように書いてみました。
let rec selectionsort ls =
    match ls with
    | [] -> ls
    | _ ->
        let min = List.min ls
        in
        (List.filter (fun x -> x = min) ls) @ (selectionsort (List.filter (fun x -> x > min) ls));;
実行してみます。
> let ls = lsSmall;;

val ls = [1; 3; 5; 7; 9; 2; 4; 6; 8]

> let beginTime = DateTime.Now;;

val beginTime :  = 2010/12/20 16:24:42

> let selectionSorted = selectionsort ls;;

val selectionSorted : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]

> let ts = DateTime.Now.Subtract(beginTime);;

val ts : TimeSpan = 00:00:00.0312500

> printfn "経過時間:%A[ms]" ts.TotalMilliseconds;;
経過時間:31.25[ms]
val it : unit = ()
>
これも、まぁこんなものかと言う結果ですね。
ここまで、ソートは正しくできているので、ひとまず良しでしょうか。



3. 挿入ソート


挿入ソートの説明はこちら↓
挿入ソート - Wikipedia

私が書いたコードはこちら↓(だんだんやっつけになってきたw)
let insertionsort ls =
    let rec insertionMain sls nls =
        match nls with
        | x::xs ->
            let rec insert_into_index ix e =
                match ix with
                | h::tl ->
                    if e <= h
                        then e::h::tl
                        else h::(insert_into_index tl e)
                | _ -> [e]
            in
            insertionMain (insert_into_index sls x) xs
        | _ -> sls @ []
    in
    insertionMain [] ls;;
よくよくコードを見渡すと、パターンマッチのdefaultに指定しているものが空のリスト([])だったり、任意(_)だったりしますね。
このあたりに、作者の思想に対する一貫性が問われそうですw

動きを確認します。
> let ls = lsSmall;;

val ls = [1; 3; 5; 7; 9; 2; 4; 6; 8]

> let beginTime = DateTime.Now;;

val beginTime :  = 2010/12/20 16:39:44

> let insertionSorted = insertionsort ls;;

val insertionSorted : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]

> let ts = DateTime.Now.Subtract(beginTime);;

val ts : TimeSpan = 00:00:00.0468750

> printfn "経過時間:%A[ms]" ts.TotalMilliseconds;;
経過時間:46.875[ms]
val it : unit = ()
>
まぁ、コメントに困ると言いますかw
まぁ、気にせず行きましょう。

続きを読む »

プロフィール
あわせて読みたい
あわせて読みたい
記事検索
Project Euler
なかのひと
アクセス解析
Coderwall
  • ライブドアブログ

トップに戻る