人権真骨頂

とくがたかいことでゆうめい

exercismをCrystalでやった

exercismってなに

exercism.io

これ.いくつか問題があって,投稿してフィードバックもらえますよみたいなやつ.

色々な言語で問題とテストケースが用意されていてCrystalもあったのでやってみた.

適当にやるとだんだんCrystalに慣れてくるかなという感じで.

リポジトリ

github.com

1 Hello World

HelloWorld クラスを定義して helloメソッドを定義して引数を指定したときはその名前を利用して Hello, NAME! ,指定されていないときは Hello, World! とする.

ポイントは

  • クラスメソッドは def self.hello
  • デフォルト引数は name = "World" という感じ
  • String Interpolationは "Hello, #{name}" という感じ

2 hamming

ハミング距離求めよってやつ

def self.compute(a, b)
    a.chars.zip(b.chars).count { |l,r| l!=r }
end

で終わりだと思っていたけどこれでは無理.... (ver. 0.20.1)

Crystalではこう

https://carc.in/#/r/1i5n

Rubyではこう

http://melpon.org/wandbox/permlink/BqnausztCf9N8nrf

これでハマった.今もよく分からん.

3. Gigasecond

109秒を与えられた Time に足せば良い.

ポイントは

  • TImeクラスに +でSpanクラスを足すことができるということ
    • Time:::Span.new(0, 0, 10**9)

4 Rna Transcription

ある文字を別の文字にするやつ.

【Ruby】gsubで複数文字を置換したかった話 | カイトズズキ日記

ここを参考にした.

class RnaComplement
  CONVERTION_TABLE = {
    "G" => "C",
    "C" => "G",
    "T" => "A",
    "A" => "U"
  }
  def self.of_dna(dna)
    dna.gsub(/#{CONVERTION_TABLE.keys.join("|")}/, CONVERTION_TABLE)
  end
end

5 Bob

与えられた入力に対して決められた文を返すやつ. case-when でやっただけ.

6 Raindrop

FizzBuzz的なやつ. このScala のやつでやってみた.

Tuple は {} こう.

    case {i % 3 == 0, i % 5 == 0, i % 7 == 0}
    when {true, false, false}
      out = "Pling"
    when {false, true, false}
      out = "Plang"
    when {false, false, true}
      out = "Plong"
    end

こんな雰囲気.

7 Leap

うるう年判定. Timeleap_year? が生えているのでそれを利用する.

https://crystal-lang.org/api/0.20.3/Time.html#leap_year%3F%28year%29%3ABool-class-method

8 Difference Of Squares

Range を利用した. to_a で配列にできるのでよしなにできる. reduce ではなくて, reduce(0) にしないと配列が空で渡ってきたときに例外が発生するので注意.

https://crystal-lang.org/api/0.20.3/Enumerable.html#reduce%28memo%2C%26block%29-instance-method

9 Pangram

与えられた文字列中で 'a'~'z' までのアルファベットが少なくとも1回出てくるか判定するやつ.

さっきみたいに Range 使って, all? 使えばよい.

10 Largest Series Product

ウォー,Scalaの sliding みたいなのほしい.....

ポイントは - slidingみたいなのを実装 - BigIntで処理する - 引数が不正のときは例外を出す

例外で new を忘れがち

# NG
# raise ArgumentError

# OK
raise ArgumentError.new("hogehoge~")

11 Bracket Push

case-when になぜかハマった. if-elsif にしたら何故か通った.謎.

以下は良くて,

https://play.crystal-lang.org/#/r/1ig8

これはダメ

https://play.crystal-lang.org/#/r/1ig6

https://play.crystal-lang.org/#/r/1iga

これもダメ

12 Sieve

エラトステネスのふるいじゃない... まぁいいや

    while !num.empty?
      prime << num.shift
      num = num.reject { |i| i % prime[prime.size - 1] == 0 }
    end

13 Roman Numerals

ローマ数字化はここを参考にした.

http://codereview.stackexchange.com/a/7939

モンキーパッチやる.

14 Atbash Cipher

最初普通に変換しただけでやったら結果が微妙に違くてよく読んだら,そのまま出すんじゃなかった.

each_slice というべんりなやつがあって.べんり.

15 Anagram

next を覚えた. https://crystal-lang.org/docs/syntax_and_semantics/next.html

16 React

これは写経する感じでやった.なんかもっと上手く書けそうなきがする.

https://crystal-lang.org/api/0.20.3/Proc.html

17 Acronym

糞ゴミ正規表現でゴリ押しした.どうするのが正解なんだろう...?

str.split(/-|\s|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z])(?=[A-Z])/).map(&.[0].upcase).join

18 Binary

baseを2にして to_i すれば終わり.

19 Run Length Encoding

ランレングス符号化やるやつ.

エンコーディングはスッとできたけど,

  def self.encode(str : String)
    str.chars.chunks { |c| c }.map { |l, r|
      next l.to_s if r.size == 1
      r.size.to_s + l.to_s
    }.join
  end

デコーディングがなんか頑張る感じになってしまった.

  def self.decode(encoded_str : String)
    str = ""

    cnt = ""
    encoded_str.chars.each { |i|
      if i.ascii_number?
        cnt += i
      else
        cnt = "1" if cnt.empty?
        str += i.to_s * cnt.to_i
        cnt = ""
      end
    }

    str
  end

20 Pascals Triangle

パスカルの三角形作るやつ.

引数が不正なときは例外を出すようにする.

21 Forth

割りとダルそうなので例を見ながら写経した.

https://github.com/exercism/xcrystal/blob/master/exercises/forth/src/example.cr

property マクロは gettersetter を提供してくれる.

Char::Reader っていうべんりなやつもある. https://crystal-lang.org/api/0.20.3/Char/Reader.html

pop_once , pop_twice で使ってる yield はここらへんの話.

ブロックと Proc | プログラミング言語 Crystal

delegate マクロで処理を委譲できる

https://crystal-lang.org/api/0.20.0/Class.html#delegate%28%2Amethods%2Ctoobject%29-macro

22 Binary Search Tree

これも例を写経する感じにした. Java, Scala以来のジェネリクス,..

include を利用すると module に定義されたメソッドをインスタンスメソッドとして利用できるようになる.

モジュール | プログラミング言語 Crystal

まとめ

Rubyやんけ〜〜〜〜!!!

次はパフォーマンスとかのあたりを読んでおきたい.

Performance · GitBook

はてなインターンの事前課題をCrystalでやった

さいしょに

この記事はCrystal Advent Calendar 2016 4日目の記事.空いていたので後から参加.

qiita.com

最近Crystalをやっている.そのときに id:shiba_yu36 さんの以下の記事を見て良さそうだったのでCrystalでもやってみた.

blog.shibayu36.org

リポジトリはこちら.

github.com

ファイル操作,日付操作,コレクション操作,エラーハンドリング,テスト周りを触ることができて良かった.

ファイル操作

File - github.com/crystal-lang/crystal

ここ見てやってた. File.read_lines だけで今回は困ることがなくて良かった.

日付操作

Time - github.com/crystal-lang/crystal

日付操作も今回は,epoch秒を Time クラスに変換して. 決められたフォーマットで出力するだけで良さそうだったので楽だった.

Time.epoch(123456789).to_s("%Y-%m-%dT%H:%M:%S")

こんな感じでできた.

コレクション操作

Enumerable(T) - github.com/crystal-lang/crystal

ここを参考にしながら,自分のScala実装を見て移植していった感じ.ScalaとCrystalでは同じ動作をするメソッドでも名前が違うのがあるので戸惑ったりした.(filter->select とか) そこらへんはRuby由来な感じ?

他にもScalaみたいな感じで,

logs.map(_.status) ってやりたいけど, logs.map { |log| log.status } ってやる感じになって不便.

エラーハンドリング

めっちゃ難しい.自分はGoの返り値でエラー返すやつに慣れているので,そもそも例外機構自体新鮮だった. begin~rescue で囲む感じで良いのかな.

でもここは囲むのが長い感じがする.Optionalみたいなのないのかな.いい方法知りたい.

https://github.com/upamune/crystal-Intern-Exercise/blob/master/src/crystal-Intern-Exercise/ltsv_parser.cr#L15-L33

例外も自分で定義して返す感じ?

https://github.com/upamune/crystal-Intern-Exercise/blob/master/src/crystal-Intern-Exercise/ltsv_parser.cr#L39-L49

それで呼び出し元でも begin~rescue する感じなのかな.よくわからん...

そこらへんRubyとか例外機構があるプログラミング言語の資料でも読めば良さそう.

テスト

うーむ. Spec.before 使おうとしたけど失敗したりしたw 普通に使えるハズだけどな...

テストは普通に should eq() の組み合わせで愚直に比較していった.もっと良いやりかたあるのかな?

describe もどういう単位で分けていけばいいのか分からん.

あと,公式の言語のテストを見ると,メソッドをどういう感じで利用するのか参考にできて良かった.

感想

namespace っていうやつ,どんな感じでわければいいのかわからん.Rubyもやってこなかったので... あと,例外処理とテストがこれでいいんだろうかみたいなのがあって,テストはもっとうまくかけそうな気がする...

いろんなトピックを一度に扱えてよかった.

はてなインターン最高.