info

書籍「7つの言語7つの世界」Rubyの章の最後の問題

method_missingテクニックを使って、CSVの一行目にある物をメソッド名にしてあとの二行をその列にある物を表示させる、attr_accessorもこんなふうに実現してるのかなあ

githubリポジトリつくったよ
http://github.com/yppp/sevenlang

# -*- coding:utf-8 -*-

class CsvRow
  def initialize(header, row)
    @header = header.map{|x| x.strip}
    @row = row.map{|x| x. strip}
  end

  def method_missing name, *args
    namest =  name.to_s
    ret = nil
    @header.zip(@row) do |x, y|
      if namest == x then
        ret = y
        break
      end
    end
    super if ret.nil?
    ret
  end
end

module ActsAsCsv
  def self.included(base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end

    module InstanceMethods
      def read
        @csv_contents = []
        filename = self.class.to_s.downcase + '.txt'
        File::open(filename) do |f|
          @headers = f.gets.chomp.split(",")
          f.each do |row|
            @csv_contents << CsvRow::new(@headers, row.chomp.split(","))
          end
        end
      end

      def each(&block)
        @csv_contents.each &block
      end

      attr_accessor :headers, :csv_contents

      def initialize
        read
      end
    end
  end
end


class RubyCsv
  include ActsAsCsv
  acts_as_csv
end

m = RubyCsv::new
m.each{|row| puts row.one}
m.each{|row| puts row.two}
m.each{|row| puts row.teeeee}

読み込ませたcsv

one,two, teeeee
lions, tigers,cat
camel, alpaca,lama

書籍「7つの言語7つの世界」でRubyの章を読み飛ばそうと思ったけど、一部の問題だけ解く

配列をハッシュにしろ

[1,2,3].zip([[4, 5, 6],5,6]).inject(Hash::new){|x, y| x[y[0]] = y[1]; x}

配列が入れ子じゃなかったら

Hash[*[1,2,3].zip([4,5,6]).flatten]

16個と4個の配列を4個と1個づつで表示させろ
eachを使って

te = Array::new(16){|x| x}
fo = Array::new(4){|x| x}

fo.each.with_index {|x, y| p [fo[y], te[x*4..x*4+3]]} 

each_sliceを使って

te = Array::new(16){|x| x}
fo = Array::new(4){|x| x}
te.each_slice(4).with_index{|x, y| p [fo[y], x]}  

Treeクラスを改造して、ハッシュを木構造に変換

class Tree
  attr_accessor :name, :children

  def initialize(arg)
    if arg[:rootname].nil? then
      @name = arg[:hash].keys[0]
      if arg[:hash].values[0].empty? then                                                                                                 
        @children = []
      else
        @children = arg[:hash].values[0].map do |x, y|                                                                                    
          Tree::new rootname: x,  hash: y
        end
      end                                                                                                                                 

    else
      @name = arg[:rootname]
      if arg[:hash].empty? then
        @children = []
      else
        @children = arg[:hash].map do |x, y|
          Tree::new rootname: x,  hash: y
        end                                                                                                                               
      end
    end
  end

  def visit(&block)
    block.call self
  end

  def visit_all(&block)
    visit &block
    children.each{|x| x.visit_all &block}
  end
end

tree = Tree::new(hash: {grandpa: {dad: {child1: [], child2: []}, uncle: {child3: [], child4: []}}})

tree.visit_all{|x| p x.name}

RubyでBrainfuck処理系作ってみた

意味無いと思うけどジャンプテーブル構築時についでに命令文字をシンボルにコンパイルするようにしてる
https://github.com/yppp/brainf_ck

# -*- encoding:utf-8 -*-

class Brainfuck
  
  class ProgramError < StandardError
  end

  def initialize(src)
    @souce = src
    @program = []
    @tape = []
    @jmptab = {}
    @pc = 0
    @cur = 0
  end

  def compile
    stack = []

    @program = @souce.chars.map.with_index do |x, y|

      case x
        when '+'
        :inc
        when '-'
        :dec
        when '>'
        :next
        when '<'
        :prev
        when '['
        stack.push y
        :lb
        when ']'
        r = stack.pop
        raise ProgramError, "]が多すぎます" if r.nil?
        @jmptab[y] = r
        @jmptab[r] = y
        :rb
        when '.'
        :dot
        when ','
        :cor
      end

    end

    raise ProgramError, "[が多すぎます" unless stack.empty?
  end

  def exec
    until @program[@pc].nil?
      @tape[@cur] ||= 0
      case @program[@pc]
      when :inc
        @tape[@cur] += 1
      when :dec
        @tape[@cur] -= 1
      when :next
        @cur += 1
      when :prev
        @cur -= 1
      when :lb
        if @tape[@cur] == 0 then
          @pc = @jmptab[@pc]
        end
      when :rb
        if @tape[@cur] != 0 then
          @pc = @jmptab[@pc]
        end
      when :dot
        print @tape[@cur].chr
      when :cor    
        $stdin.getc
      end
      @pc += 1
    end
  end
end

bf = Brainfuck::new "+++++++++[>+++++++++[<[>>+>+<<<-]>>>[<<<+>>>-]<.><<-]>[-]<<-]"
bf.compile
bf.exec

Brainfuck言語やってみた

九九を9の段から1の段までASCII文字じゃなく数字として出力

+++++++++
[>+++++++++
[<[>>+>+<<<-]>>>[<<<+>>>-]<.><<-]
>[-]<<-]

使うメモリの番地
0 出力する段の数
1 足す回数のカウンタ
2 結果になる値
3 コピーのための0番地に戻すテンポラリ領域

http://cfs.maxn.jp/neta/onlineBrainFuck.html
での出力

[HT][DC2][ESC]$-6?HQ[BS][DLE][CAN] (08@H[BEL][SO][NAK][FC]#*18?[ACK][NP][DC2][CAN][RS]$*06[ENQ]
[SI][DC4][EM][RS]#(-[EOT][BS][NP][DLE][DC4][CAN][FC] $[ETX][ACK][HT][NP][SI][DC2][NAK][CAN][ESC][STX][EOT][ACK][BS]
[NP][SO][DLE][DC2][SOH][STX][ETX][EOT][ENQ][ACK][BEL][BS][HT]

http://brainfuck.bake-neko.net/bfi.html
http://www.iamcal.com/misc/bf_debug/
いろいろな処理系を使ってみると吉

RubyKaigi2011に行ったかんそう

こころにのこったはっぴょう、いくつか


parse.yは簡単に改造できる


Rubyでなんでも使いこなせると思うには
1.標準ライブラリをさわる
2.きれいなコードを書くこころがけ(副作用がある操作のおすすめはeachよりmap!らしい)
3.gemやRuby本体を改造する


matz曰く、日本は「蠱毒
言語自体のカンファレンスでこんなに人が集まって何年も続くのは日本だけらしい、日本語の言語制作本もたくさん出ているしたくさんの言語ができてる、Rubyはその中の生きのこった虫になりたいと言った
ライバルは「全力で潰す」そうかそうか

scheme(gauche)で世界のナベアツ問題

3がつく数と3の倍数の時だけアホになる(片仮名になる)それ以外は普通に数字を表示
peercastの大会で課題だったので、っていうか就活の課題やれ俺www

(use srfi-1)
(use srfi-13)

(define (unpack x y)
  (if (= x 0)
      y
      (unpack (quotient x 10) (append  (list (modulo x 10)) y))))

(define (3baisu? x) (= (modulo x 3) 0))

(define (3gatuku? x)
  (any (lambda (i) (= i 3)) (unpack x '())))

(define (senkurai x)
  "セン")

(define (hyakukurai x)
  (ref '( ""  "ヒャク"  "ニヒャク" "サンビャク" "ヨンヒャク" "ゴヒャク" "ロッピャク" "ナナヒャク" "ハッピャク" "キュウヒャク") x))

(define (jukurai x)
  (ref '( "" "ジュウ" "ニジュウ" "サンジュウ" "ヨンジュウ" "ゴジュウ" "ロクジュウ" "ナナジュウ" "ハチジュウ" "キュウジュウ") x))

(define (ichikurai x)
  (ref '( "" "イチ" "ニ" "サン" "ヨン" "ゴ" "ロク" "ナナ" "ハチ" "キュウ") x))

(define func  `(() ,ichikurai ,jukurai ,hyakukurai ,senkurai))

(define (tokatakana x)
  (let loop ((lis (unpack x '())) (kana ""))
    (if (= (length lis) 0)
	kana
	(loop (cdr lis) (string-append kana ((ref func (length lis)) (car lis)))))))
		    

(for-each print (map (lambda (x)
		       (if (or (3baisu? x) (3gatuku? x))
			   (string-append (tokatakana x) "!")
			   x))
		       (iota 1000 1 1)))


出力の最後のほう

950
キュウヒャクゴジュウイチ!
952
キュウヒャクゴジュウサン!
キュウヒャクゴジュウヨン!
955
956
キュウヒャクゴジュウナナ!
958
959
キュウヒャクロクジュウ!
961
962
キュウヒャクロクジュウサン!
964
965
キュウヒャクロクジュウロク!
967
968
キュウヒャクロクジュウキュウ!
970
971
キュウヒャクナナジュウニ!
キュウヒャクナナジュウサン!
974
キュウヒャクナナジュウゴ!
976
977
キュウヒャクナナジュウハチ!
979
980
キュウヒャクハチジュウイチ!
982
キュウヒャクハチジュウサン!
キュウヒャクハチジュウヨン!
985
986
キュウヒャクハチジュウナナ!
988
989
キュウヒャクキュウジュウ!
991
992
キュウヒャクキュウジュウサン!
994
995
キュウヒャクキュウジュウロク!
997
998
キュウヒャクキュウジュウキュウ!
1000

luaでメタプログラミング(DSL)

宣言、luaは引数が文字列リテラル、テーブルリテラルだと、括弧が省略できる、ここではgenerateという関数を作っている、ようするに何かを操作する関数を作ればいい

generate "iroiro"

文脈依存、luaにはRubyやCommonLispのような、instance_evalのみたいなダイナミックスコープを扱う仕組みがない、だから文脈依存を使いたい時はオブジェクトを受けとる、もしくはテーブルを引数にしてもいい

pokemon_add (function(dep)
 dep.name = "pikacyu"
 dep.actor_type_is "enemy"
 dep.pokemon_type_is "denki")

--もしくは

pokemon_add {
 name = "pikacyu",
 actor_type = "enemy",
 pokemon_type_is = "denki"}

単位、ちょっと苦しいか?

mega(5) + kiro(100) + 500
>5100500

語彙、luaのmethod_missingはメタテーブルの__indexメソッドを再定義すればいい、もちろんグローバルでも有効、上のpokemon_addを定義してみる

setmetatable(_G, {
 __index = function(t, k)
return function(...) 
local objname,member = string.match(objname, "^(.+)_(.+)")
if(objname == "pokemon") then
_G[objname][member](...)
else
error(...)
end
end})

function pokemon:new()
local t = {actortype = nil, nigatetype= nil, tokuitype = nil}
setmetatable(t, {})
return t
end

function pokemon:add (f)
f(self)
end

--宣言に加えたい物をメソッドとして加えていく

階層データ、luaはもともとデータファイルとして開発された、テーブルにテーブルを入れ子にすればいい


感想、"function"っていちいち打つのがめんどくさい、Rubyで言うブロックが欲しいって思う
Lispだってlambdaって打つのがめんどくさいけどまだ打つのが楽w キーボードで上の段使ってない
function うつとき縦の動きがあるお、あとダイナミックスコープの必要性を知った