「レッスンは何曜日?」をFactorで(横へな21)


レッスンは何曜日?」をFactorでやってみました。他の皆様による実装は 第21回オフラインリアルタイムどう書くの問題 から辿れます。

次のような方針で解きました。

  1. 各クラスについて最優先で希望している社員を配属する
  2. 各クラスを先頭4人だけに絞る
  3. 配属され先頭4人に入った人をリストから削除する
  4. 未配属の人の希望クラスの1番目を消し、2番目を1番目に移動する
  5. 全員の希望クラスがなくなるまで、1の手順に戻って繰り返す
21lesson.factor
USING: kernel sequences sequences.deep math math.order math.parser
       arrays splitting assocs sorting ;
IN: 21lesson

! 希望リストから配属候補を求める
: wish-list>candidate ( wish-list -- candidate )
    { 1 2 3 4 5 } swap [
        [ second first over = ] filter
        [ first ] map swap drop
    ] curry map ;

! 先頭4つだけにする
: only4 ( seq -- seq ) dup length 4 min head ;

! 配属リストに候補を追加する
: append-candidate-to-assigned ( assigned candidate -- assigned' )
    [ append only4 ] 2map ;

! 配属された社員を希望リストから削除する
: delete-assigned-from-wish-list ( assigned wish-list -- wish-list' )
    swap flatten [ swap first swap index not ] curry filter ;

! 希望リストの順位を繰り上げる
: shift-wish-list ( wish-list -- wish-list' )
    [ dup first swap second rest { } 2sequence ] map ;

! 最も高い希望を配属する
: assign-first-wish ( assigned wish-list -- assigned' wish-list' )
    [ wish-list>candidate append-candidate-to-assigned ] keep
    dupd delete-assigned-from-wish-list
    shift-wish-list ;

! 配属する
: assign-wish ( wish-list -- assigned )
    { { 0 { 0 0 0 0 0 } } } append
    5 { } <array> swap
    5 [ assign-first-wish ] times
    drop ;

! 入力文字列を希望リストに変換する
: >wish-list ( str -- wish-list )
    "|" split [ "_" split [ first string>number ]
        [ second [ digit> ] { } map-as ] bi { } 2sequence ] map ;

! 配属リストを文字列に変換する
: assigned>string ( assigned -- str )
    { 1 2 3 4 5 } swap zip
    [ second length 0 = not ] filter
    [
        dup first number>string "_" append
        swap second natural-sort
        [ number>string ] map ":" join append
    ] map "|" join ;

! 解く
: solve ( str -- str ) >wish-list assign-wish assigned>string ;

Factorを始めました。自分で書いたコードなのに数日経ったら読めません (^^;)

Factorは連鎖性プログラミング言語です。多くのプログラミング言語が func(arg1, arg2)(func arg1 arg2) という語順なのに対して、Forthを始めとする連鎖性言語は arg1 arg2 func という語順で書きます。通常は変数を使わず、引数をスタックに積んで関数(ワード)を呼び出すと、結果がスタックに積まれて返ってきます。JVM(Java仮想マシン)のニーモニックを直接書いている雰囲気ですが、クォーテーション(無名関数)を使ったmapやfilterなど、関数型言語に似ている部分があります。