class が export キーワードで export できなくてちょっと悲しかった

node のバージョンはこんな感じ:

% node --version
v6.3.1

wasp を書いてたら、

// ↓ class は書けるのに、export ができない!!!><
/* export */ class Emitter {
    constructor() {
        this.events = [];
    }

    on(name, cb) {
        this.events = ( this.events || [] );
        this.events[name] = cb;

        return this;
    }

    emit(name, that) {
        let self = this;

        let events = self.events[name] || [];

        events.forEach( anEvent => {
            anEvent.call( self, that );
        } );
        return self;
    }
}

// ↓ ので、従来通りの module.exports に Emitter を設定する。
module.exports = Emitter;

という感じだったので、悲しい。

ビルドツール Wasp とかどうかな

Fly を見ていたらこういう風に書けたって良いんじゃないかなと思った:

const gcc = require( 'wasp-gcc' );

const paths = {
    scripts: [ 'src/**/*.c' ],
    dist: 'obj'
};

export default function () {
    this.ready( 'build' );
}

export function compile() {
    this.from( paths.scripts )
        .gcc()
        .to( paths.dist );
}

うん、source() とか target() じゃなくて、from() とか to() って書けた方が良いと思う。

モジュールが Fly オブジェクトのメソッドを使えるようにするのってどうするんだーーーー?

Nemerle やってみた

インストール

yaourt でインストールできる:

% yaourt -S nemerle

へろーわーるど

using System;

Console.WriteLine( "Hello, World!" );

このファイルを hello.n とすると、ncc を使ってこんな風にコンパイルできる:

% ncc ./hello.n -o hello.exe

関数

関数は def から始まる:

def add(a : int, b : int) : int {
    a + b;
}

FParsec のチュートリアル的な何か

さて、今日は FParsec 日本語チュートリアルを読んでやってみるよ。

nuget はインストールしてるかな?
私は nuget3 をインストールしてみたよ:

% yaourt -S nuget3

勉強用のディレクトリを作成しよう:

% mkdir ./hello-fparsec
% cd ./hello-fparsec

FParsec をインストールしてみよう:

% nuget install FParsec -outputDirectory ./packages

-outputDirectory ./packages を付けない場合、カレントディレクトリに FParsec がインストールされてしまうので注意だ。
なので、Visual Studio の慣習に習って ./packages/ にインストールしてみた。

さっそく使ってみる

run 関数に何らかのパーサー関数と文字列を渡すと結果が返ってくる模様。

ʕ•͡ω•ʔ pfloat は FParsec 浮動小数点数をパースして浮動小数点数を返す組み込みのパーサー関数だぞ

// demo000.fsx
open FParsec


let test p str =
  match run p str with
    | Success(result      , _, _)   -> printfn "Success: %A" result
    | Failure(errorMessage, _, _)   -> printfn "Failure: %s" errorMessage

test pfloat "1.25"
test pfloat "1.25E"
test pfloat "1.25E 3"

それで、こんな風に打ってみると:

% fsharpi -I ./packages/FParsec.1.0.2/lib/net40-client/ -r "FParsec.dll" ./demo000.fsx
Success: 1.25
Failure: Error in Ln: 1 Col: 6
1.25E
     ^
Note: The error occurred at the end of the input stream.
Expecting: decimal digit

Failure: Error in Ln: 1 Col: 6
1.25E 3
     ^
Expecting: decimal digit

最初の test pfloat "1.25" だけパースされた。

ヽ(=´▽`=)ノ

OCaml の Test::Simple を目コピしてみた その 4

OCamlソースコードに沿って TAPDocument.ml を test-document.fs にして、TAPBuilder.ml を test-builder.fs に書いてみた。

なんかクラスっぽいやつでやってみたんだけど、これでいいのかな…………(汗

module Test.Builder

type Plan(?count : int) =
  let current_plan : option<int> = count

type TestCaseBuilder () =
  let mutable running_tests : (int -> Test.Document.node) list = [];

  member this.BuildTestCase(todo : option<string>, diag : option<Test.Document.diagnostic>, test : bool, description : string) =
    let running_test = fun number ->
      match todo with
        | None          -> Test.Document.TestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk),
                                                      number,
                                                      description,
                                                      diag)
        | Some x        -> Test.Document.TodoTestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk),
                                                          number,
                                                          description,
                                                          Test.Document.Todo(x),
                                                          diag)
    running_tests <- running_test :: running_tests
    running_test

  member this.BuildDiagnostic(line : string) =
    let running_test = fun (_ : int) ->
                       Test.Document.DiagnosticNode (Test.Document.Diag( [ line ] ))
    running_tests <- running_test :: running_tests
    running_test

今ブログ記事を書いてる時に気がついたけど、これじゃダメだよねwwwwww

だって、Plan とか let plan = Plan(12) とかってしないとわかんないじゃんwwwwww ほげーーーーーーー!!!

あと、F# では、関数に省略した引数を使えないので、typeコンストラクタ?の引数に使わなければならない………

(。・_・。) ………

TestCaseBuilderTestCaseResult とかにして、そのリストをどこかに持ったほうが良いのかも?
こんな感じ:

type TestCase(?todo, ?diag, test, description) =
  let running_test = fun number ->
      match todo with
        | None          -> Test.Document.TestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk),
                                                      number,
                                                      description,
                                                      diag)
        | Some x        -> Test.Document.TodoTestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk),
                                                          number,
                                                          description,
                                                          Test.Document.Todo(x),
                                                          diag)

OCaml の Test::Simple を目コピしてみた その 3

続き。

ʕ•͡ω•ʔ TAPDocument.ml 完全目コピでけたー!

init_document はなんか初期化しそう。

let init_document doc =
  let count     = count_tests         doc in
  let failures  = count_test_failures doc in
  match doc with
  | Document(PlanNode(plan)::nodes) ->
     Document(
         PlanNode(plan)::nodes
         @
           (if count = plan then [] else [ (create_count_footer count plan) ] )
         @
           (if failures = 0 then [] else [ (create_failure_footer count failures) ])
       )
  | Document(nodes)                 ->
     Document(
         nodes
         @
           [ PlanNode(count) ]
         @
           (if failures = 0 then [] else [ (create_failure_footer count failures) ])
       )

後は文字列化する関数。

そんでさ、function Document(nodes) -> は Warning 出るけど、どーすれば回避できるかわかんないって書いたけど、わかった。
let hoge Document nodes = ... でいいみたい。
引数が複数あってわけわかんない場合は let piyo (Document nodes) = みたいに括弧つけとこう。

let string_of_status status =
  match status with
  | OK          -> "ok"
  | NotOk       -> "not ok"
let string_of_diagnostic (Diag lines) =
  List.map (fun line -> "# " + line + "\n") lines
  |> List.fold (+) ""

こことかかっこよく |>(パイプライン) つこうた

let string_of_directive (Todo s) =
  "# TODO " + s
let string_of_node node =
  let emit_diagnostic diag =
    (match diag with
     | None          -> "\n"
     | Some diag     -> "\n" + (string_of_diagnostic diag))
  in
  match node with
  | TestCaseNode(status, num, desc, diag)          ->
     (string_of_status status)
     + " "
     + num.ToString()
     + " - "
     + desc
     + (emit_diagnostic diag)
  | TodoTestCaseNode(status, num, desc, dir, diag) ->
     (string_of_status status)
     + " "
     + num.ToString()
     + " - "
     + desc
     + (string_of_directive dir)
     + (emit_diagnostic diag)
  | DiagnosticNode(diag)                           ->
     (string_of_diagnostic diag)
  | PlanNode(count)                                ->
     "1.." + count.ToString() + "\n"
let string_of_document (Document nodes) =
  List.map string_of_node nodes
  |> String.concat "" 

ここも。

全部のソースはここに置いてある。

OCaml の Test::Simple を目コピしてみた その 2

続き。

OCaml では文字列の結合は ^ だけど*1、F# では + だ。
また、OCaml での string_of_int は F# には存在しないけど、書くとしたらこんな感じになる:

let string_of_int (n:int):string =
  n.ToString()

DiagnosticNode を返す関数 2 連発:

let create_failure_footer test_count failure_count =
  DiagnosticNode(
    Diag(["Looks like you failed "
          + failure_count.ToString()
          + " tests of "
          + test_count.ToString()
          + " run."])
    )
let create_count_footer test_count plan_count =
  DiagnosticNode(
    Diag(["Looks like you planed "
          + plan_count.ToString()
          + " tests but "
          + (if test_count < plan_count then
               ("only ran " + test_count.ToString())
             else
               ("ran " + ((test_count - plan_count).ToString()) + " extra"))
          + " ."])
    )

*1:F# でも Warning は出るものの、使うことができる

OCaml の Test::Simple を目コピしてみた

これ

普通に OCaml のコードがコンパイルできるのすごい。

モジュール名は Test.Builder にしておく。

module Test.Builder

type status =
  | NotOk
  | Ok

type directive =
  | Todo of string

type diagnostic =
  | Diag of string list

type node =
  | TestCaseNode     of status * int * string * diagnostic             option
  | TodoTestCaseNode of status * int * string * directive * diagnostic option
  | DiagnosticNode   of diagnostic
  | PlanNode         of int

type test_document =
  | Document of node list

テストケースをノードとして管理?する。
test_document が一番トップの型みたいだ。

let rec count_test_nodes nodes count =
  match nodes with
    | []                                   -> count
    | TestCaseNode(_, _, _, _)::xs
    | TodoTestCaseNode(_, _, _, _, _)::xs  -> count_test_nodes xs count + 1
    | DiagnosticNode(_)::xs
    | PlanNode(_)::xs                      -> count_test_nodes xs count

関数 count_test_nodes はノードの数を数える。
具体的には TestCaseNodeTodoTestCaseNode を数える。

let count_tests = function Document(nodes) ->
  count_test_nodes nodes 0

count_tests は引数が test_document だった時用の count_test_nodes だ。

function Document(nodes) -> は Warning を発生させる。
この Warning をどうやって回避すれば良いのかは不明である。

let count_test_failures = function Document(nodes) ->
  let rec loop nodes count =
    match nodes with
    | []
      -> count
    | TestCaseNode(Ok, _, _, _)::xs
    | TodoTestCaseNode(Ok, _, _, _, _)::xs
    | DiagnosticNode(_)::xs
    | PlanNode(_)::xs
      -> loop xs count
    | TestCaseNode(NotOk, _, _, _)::xs
    | TodoTestCaseNode(NotOk, _, _, _, _)::xs
      -> loop xs count + 1
  in loop nodes 0

関数 count_test_failures は指定されたノードリストの中から失敗したノードの数を数える。

書いたのは ここ に置いとく。