“Lisp as an Alternative to Java”のお題を Squeak Smalltalk で


何を見てだったかは失念^^;…経由で http://www.kmonos.net/alang/d/2.0/lisp-java-d.html を知って、面白そうだったのでチャレンジ。こんなのは33分くらいあれば十分!とナメてかかったものの、結局、なんやかんやあって3時間くらいかかっちゃいました。なんやかんやは…なんやかんやです。w

古めのネタですが、イチオシの言語や処理系やパラダイムがあれば、その“パワー”の違いを他との比較をつうじて見定めるのに、あるいは、使い慣れた or 学習中の 言語や処理系やパラダイムを用いての自らのスキルや理解度をはかる腕試しに、FizzBuzz ほど簡単ではない適度な手応えがあってよさそうに思いました。


要件はおおざっぱにはこんな感じでしょうか。

  • 指示に従い、アルファベットを0〜9の数字に割り振る。
  • 記号を含む数字列をこの対応表を用いて数字以外を無視して符号化し、与えられた辞書に含まれる単語の組み合わせで表現可能な場合を探して列挙。
  • 適当な単語が見つからないときに限り、連続しないように数字を残してもよい。


くわしくはこちらをご覧ください。

| groups words phones dict results queue |

groups := #('jnq' 'rwx' 'dsy' 'ft' 'am' 'civ' 'bku' 'lop' 'ghz' 'e').
words := #('an' 'blau' 'Bo"' 'Boot' 'bo"s' 'da' 'Fee' 'fern' 'Fest' 'fort' 'je' 'jemand'
    'mir' 'Mix' 'Mixer' 'Name' 'neu' 'o"d' 'Ort' 'so' 'Tor' 'Torf' 'Wasser').
phones := #('112' '5624-82' '4824' '0721/608-4067' '10/783--5' '1078-913-5' '381482' '04824').

[   | url |
    url := 'http://www.flownet.com/ron/papers/lisp-java/'.
    words := (HTTPSocket httpGet: url, 'dictionary.txt') contents subStrings: String lf.
    phones := (HTTPSocket httpGet: url, 'input.txt') contents subStrings: String lf] "value".

dict := Dictionary new.
words do: [:word |
    | key |
    key := (word copyWithout: $") collect: [:each |
        (groups findFirst: [:group | group includes: each asLowercase]) asString last].
    (dict at: key ifAbsentPut: (OrderedCollection new)) add: word].

results := Dictionary new.
queue := OrderedCollection new.
phones do: [:phone |
    queue add: {phone. phone select: [:each | each isDigit]. OrderedCollection new}].
[queue notEmpty] whileTrue: [
    | data |
    queue size asString, ' ' displayAt: 0 asPoint.
    data := queue removeFirst.
    data second
        ifEmpty: [(results at: data first ifAbsentPut: [OrderedCollection new]) add: data last asArray]
        ifNotEmptyDo: [:rest |
            (dict keys select: [:key | rest beginsWith: key])
                ifEmpty: [(data last isEmpty or: [data last last size > 1]) ifTrue: [
                    data last add: (rest first: 1).
                    rest := rest allButFirst.
                    queue add: {data first. rest. data last}]]
                ifNotEmptyDo: [:founds |
                    founds do: [:found |
                        | next segs |
                        next := rest allButFirst: found size.
                        segs := data last copyWith: found.
                        next size = 1 ifTrue: [segs add: next. next := ''].
                        queue add: {data first. next. segs}]]]].

World findATranscript: nil.
phones do: [:phone |
    (results at: phone ifAbsent: [#()]) do: [:segs |
        queue := OrderedCollection with: {segs. ''}.
        [queue notEmpty] whileTrue: [
            data := queue removeFirst.
            data first
                ifEmpty: [Transcript cr; show: phone, ': ', data last allButFirst]
                ifNotEmptyDo: [:rest |
                    (dict at: rest first ifAbsent: [{rest first}])
                        do: [:word | queue add: {rest allButFirst. data last, ' ', word}]]]]]


最初のほうの "value" のコメントアウトを外せば、こちらで与えられている大きめのデータを使った処理が可能です。