コラッツ予想がとけたらいいな2

自分の考察を書いていきます。

Crystal をやってみた その3(フィボナッチ)

フィボナッチができた。


# crystal test4.cr

# 遅延評価
class Delay
  def initialize(&block : String -> Int32)
    @func = block
    @flag = false
    #@value = nil
    @value = 0
  end
  def force
    unless @flag
      ret = @func.call ""
      @value = ret.nil? ? raise("@func.call is nil. #{@func}") : ret
      @flag = true
    end
    @value
  end
end

# Bool 構造体にメソッドを追加
struct Bool
  def if(t, e)
    return t.responds_to?(:force) ? t.force : t if self
    e.responds_to?(:force) ? e.force : e
  end
end
# puts true.if "then", "else"

struct Int
  # 階乗
  def fact
    self.<=(0).if 1, Delay.new{self.-(1).fact.*(self)}
  end
  # フィボナッチ
  def fib
    self.<=(1).if (self.==(0).if 0, 1), Delay.new{self.-(1).fib.+(self.-(2).fib)}
  end
end

# 実行
puts 10.fact # => 3628800

puts (0..10).to_a.map &.fib # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]




Crystal をやってみた その2(メソッドチェーン)

関連


メソッドチェーンでプログラムを書くことを考えている。
BoolInt にメソッドを追加して、ひとまず今の形になった。


階乗のプログラム

# crystal test4.cr

# 遅延評価
class Delay
  def initialize(&block : String -> Int32)
    @func = block
    @flag = false
    #@value = nil
    @value = 0
  end
  def force
    unless @flag
      ret = @func.call ""
      @value = ret.nil? ? raise("@func.call is nil. #{@func}") : ret
      @flag = true
    end
    @value
  end
end

# Bool 構造体にメソッドを追加
struct Bool
  def if(t, e)
    if_base t, e
  end

  def if_base(t, e)
    return t.responds_to?(:force) ? t.force : t if self
    e.responds_to?(:force) ? e.force : e
  end
end
# puts true.if "then", "else"

struct Int
  # 階乗
  def fact
    self.<=(0).if 1, Delay.new{self.-(1).fact.*(self)}
  end
end

# 実行
puts 10.fact # => 3628800


ここまでで分かった事

ブロック引数には型をつけなくてはいけない

現状、結果の型が Int32 に固定されている

マクロはインスタンスメソッド扱いでなく、クラスメソッド扱い

true.macro_if... じゃなくて Bool.macro_if... になってしまう
これでは目的に合わない

引数は先行評価される

if で選ばれない方は評価したくないので、本方式となった


続くかな?




Haskell の Arrow の練習 その2(FizzBuzz 2)

参考記事

前回


前回の最後の代わり

fb = proc x -> do
  e <- arr (uncurry (++)) <<< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5) -< x
  arr (uncurry (++)) <<< (arr (uncurry r) <<< show *** (=="")) &&& snd -< (x, e)

こっちの独自路線でいこう。
(arr (uncurry r) <<< show *** (==""))の部分は、
Fizz Buzz FizzBuzz でなかったら数値を show したものを吐くんだね。


仕上げ

fb = proc x -> do
  arr (uncurry (++)) <<< (arr (uncurry r) <<< show *** (=="")) &&& snd <<<
    id &&& (arr (uncurry (++)) <<< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5)) -< x

参考記事のほうはおそらく、カッコを減らすために、関数合成で区切りを入れているのだと思う。

proc を消して、

fb = arr (uncurry (++)) <<<
  (arr (uncurry r) <<< show *** (=="")) &&& snd <<<
    id &&& (arr (uncurry (++)) <<< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5))

最後に arr (uncurry (op))演算子化して完成だ。

infixr 2 <+<
(<+<) op f = arr (uncurry op) <<< f

fb = (++) <+<
  (r <+< show *** (=="")) &&& snd <<<
    id &&& ((++) <+< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5))


いやー、これはすごいね。暗号みたいでかっこいい。




Haskell の Arrow の練習(FizzBuzz)

参考記事


まず Arrow 記法で書く

{-# LANGUAGE Arrows #-}
module FizzBuzz where

import Control.Arrow ( (<<<), Arrow(arr) )

r :: String -> Bool -> String
r s b = if b then s else ""

fb :: Integer -> String
fb = proc x -> do
  a <- (==0) . (`mod`3)   -< x
  b <- (==0) . (`mod`5)   -< x
  c <- r "Fizz"           -< a
  d <- r "Buzz"           -< b
  e <- arr (uncurry (++)) -< (c, d)
  f <- (=="")             -< e
  g <- arr (uncurry r)    -< (show x, f)
  arr (uncurry (++)) -< (g, e)

main :: IO ()
main = mapM_ (putStrLn <<< fb) [1..40]


ここからワンライナーにしていく

a,b は一箇所しか現れないので合体させる

&&&*** を使う(並列的なアロー)

(&&&) :: a b c -> a b c' -> a b (c, c') infixr 3
(***) :: a b c -> a b' c' -> a (b, b') (c, c') infixr 3

fb = proc x -> do
  e <- arr (uncurry (++)) <<< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5) -< x
  g <- arr (uncurry r) <<< show *** (=="") -< (x, e)
  arr (uncurry (++)) -< (g, e)

ごにょごにょ

fb = proc x -> do
  e <- arr (uncurry (++)) <<< r "Fizz".(==0).(`mod`3) &&& r "Buzz".(==0).(`mod`5) -< x
  arr (uncurry (++)) <<< arr (uncurry r) *** id <<< (show *** (=="")) &&& snd -< (x, e)

うーん、ここがよく分からない。今日はここまでにしよう。




Crystal をやってみた

なんとなく Crystal をやってみた。
環境は Linux(Ubuntu) だ。

インストール

https://ja.crystal-lang.org/install/ から。
Windows では WSL を使うようだ。

VSCode

https://github.com/crystal-lang-tools/vscode-crystal-lang が良いらしい。

Hello World

適当な場所に test.cr を作って、以下のように書く。

puts "Hello World!"

そして $ crystal test.cr 。これできみも Crystaler だ!

この後ごにょごにょやってたけど、
全然いけてないプログラムになったのでお蔵入り。
パースの仕方を勉強したいな。