Web上の情報とか

ここまで Adobe のページ。ここからは参考にした記事など。

開発ツール

無償の開発ツールとしては,Adobe から2つ配布されている。

  • Adobe AIR SDK
  • Flex 3 SDK

AIR SDK のほうは HTML + JavaScript ベースの開発ツールみたい。今回は Flex ベースの Flex 3 SDK を使う。

どっちも http://www.adobe.com/jp/products/air/tools/ からダウンロードできる……と思ったら,あれ?今見たら Flex 3 SDK が Adobe Flex Builder 3.0.1 Professional(有償,60日間体験版)へのリンクになってる。おかしいな,こないだは Flex 3 SDK だったはずなのに。どこへ行った?

Adobe AIRに手を出した

ブログもOCamlもほったらかし(一応「プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」は最後まで読んだ)のままだったけど,最近はAdobe AIRに手を出した。

AIR は Adobe Integrated Runtime の略で,RIA(Rich Internet Application)をデスクトップアプリとして実行する環境。しかもクロスプラットフォーム。AIRアプリの開発手法には3つあって:

  • HTML + css + Javascript(Ajax含む)
  • Flash
  • Flex

のどれでも開発が出来る。Flash と Flex がどう違うのかいまいちわかんないんだけど,要するに Webアプリの開発手法をそのまま使えるってことらしい。

で,とりあえず見よう見まねで Hello world じゃなくて Hello AIR を Flex ベースで作ってみた。

HelloAIR.mxml

<?xml version="1.0" encoding="utf-8"?>
 <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
                         layout="absolute"
                         title="Hello AIR">
 
   <mx:Script>
     <![CDATA[
       private function hello():void {
         myLabel.text = "Hello AIR!";
       }
     ]]>
   </mx:Script>
 
   <mx:Label id="myLabel" horizontalCenter="0" verticalCenter="0"/>
   <mx:Button id="myButton" label="click" horizontalCenter="0" verticalCenter="20" c lick="hello();"/>
 
 </mx:WindowedApplication>

HelloAIR-app.xml

<?xml version="1.0" encoding="utf-8"?>
 <application xmlns="http://ns.adobe.com/air/application/1.1" minimumPatchLevel="0"> 
   <id>com.websysd.flex.HelloAIR</id>
   <version>1.1</version>
   <filename>HelloAIR</filename>
   <initialWindow>
     <content>HelloAIR.swf</content>
     <systemChrome>none</systemChrome>
     <visible>true</visible>
     <width>400</width>
     <height>200</height>
   </initialWindow>

必要なファイルは:

  • ソースファイル(HelloAIR.mxml)
  • アプリケーション記述ファイル(HelloAIR-app.xml)

の2つ,というか2種類。

ソースを記述する言語にも2つあって,1つは画面構成を記述する MXML,もう1つは動作を記述する ActionScript。HTML と JavaScript の関係と同じだと思えばいい。

アプリケーション記述ファイルには,ウィンドウの大きさとかインストール先とかを書く。アプリの名前に -app をつけたのをファイル名にするのが普通らしい。

コンパイルには amxmlc コマンドを使う。

^o^ >amxmlc HelloAIR.mxml
設定ファイル "C:\usr\Flex3SDK\frameworks\air-config.xml" をロードしています
D:\Documents\24711\My Documents\work\AIR\HelloAIR\HelloAIR.swf (255199 bytes)

これで,HelloAIR.swf ファイルが出来る。

開発中はインストールしなくても実行できるように,adl コマンドがある。adl コマンドにはアプリケーション記述ファイルを引数として与える。

^o^ >adl HelloAIR-app.xml

実行画面(ボタンを押して,メッセージが表示されたところ)

f:id:takatoh:20081102225153j:image

本も買った。

AIRプログラミング入門 1.1日本語版対応

 

AIRプログラミング入門 1.1日本語版対応

-1 を 10 で割ったあまりは?

どう書く?org のこのお題,はじめはHaskellで書いた。

modular n l h = l + n `mod` (h - l + 1)

すでに投稿があったのでOCamlで書き直したんだけど,そのまま移植したんではうまくいかない。

# let modular n l h = l + n mod (h - l + 1);;
val modular : int -> int -> int -> int = <fun>
# modular (-1) 100 200;;
- : int = 99

しばらく悩んだけど,要するに mod の引数に負数が現れた場合の振る舞いが Haskell と OCaml で違う。思わぬ盲点だよな。

Haskellの場合:

Prelude> mod (-1) 10
9
Prelude> mod 1 (-10)
-9

OCamlの場合:

# (-1) mod 10;;
- : int = -1
# 1 mod (-10);;
- : int = 1

さて,算術的にはどっちが正しいんだろうか。

METHINKS IT IS LIKE A WEASEL

cf. どう書く?org – METHINKS IT IS A WEASEL

ずいぶん前に「ブラインドウォッチメイカー」を読んだ書いてみたもの。出遅れだし,お題ともちょっと違うので投稿せずにここにさらしておく。

IDEAL = "METHINKS IT IS LIKE A WEASEL"
class Individual
def initialize(phenotype)
@phenotype = phenotype.upcase
end
attr_reader :phenotype
def delivery
next_phenotype = @phenotype.dup
next_phenotype[rand(@phenotype.size)] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ".slice(ra nd(27), 1)
Individual.new(next_phenotype)
end
def breed(n)
next_generation = []
n.times do
next_generation << delivery
end
next_generation
end
def to_s
@phenotype
end
end
class Nature
def initialize(ideal)
@ideal = ideal
end
def select(group)
r = []
max = 0
group.each do |i|
s = evaluate(i)
if s > max
max = s
r = [i]
elsif s == max
r << i
end
end
r[0]
end
def evaluate(ind)
phenotype = ind.phenotype
score = 0
0.upto(@ideal.size - 1) do |i|
score += 1 if phenotype[i] == @ideal[i]
end
score
end
end
if __FILE__ == $0
require 'optparse'
def err_exit(msg)
$stderr.print msg
exit
end
options = {:number => 100}
opts = OptionParser.new
opts.banner = "Usage: ruby miilaw.rb [option] initial\n"
opts.on_tail('-h', '--help', 'show this massage.') {puts opts; exit(0)}
opts.on('-n', '--number=NUM', Integer, 'set number of children.') {|options[:numbe r]|}
opts.parse!
err_exit(opts.help) if ARGV.empty?
len = IDEAL.size
init = ARGV.shift.upcase
if init.size < len
init = "%-#{len}s" % init
elsif init.size > len
init = init[0,len]
end
individual = Individual.new(init)
nature = Nature.new(IDEAL)
genaration = 0
print "#{genaration} : #{individual}\n"
while true do
genaration += 1
next_gen = individual.breed(options[:number])
individual = nature.select(next_gen)
print "#{genaration} : #{individual}\n"
break if individual.phenotype == IDEAL
end
end

練習問題 10.3 fold コマンド

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~のp.215より。

wc コマンドはなんか難しいのでこっちを先に。

UNIX の fold コマンドは,ファイル名の列を引数として,その内容を,長い行を複数の短い 行(デフォルトでは80文字)に分割しながら表示します。これを OCaml で実装し,実行可能 ファイルを作成しなさい。オプションとしては,行の長さを整数で指定する –width を実装 しなさい。

let version = "0.1"
let filenames = ref []
let width = ref 80
let spec = [("--width",
Arg.Int (fun n -> width := n),
"Set line width");
("--version",
Arg.Unit (fun () -> Printf.printf "fold in OCaml ver.%s\n" version),
"Display version")]
let rec fold_line n str =
let len = String.length str in
if len > n then
( print_endline (String.sub str 0 n);
fold_line n (String.sub str n (len - n)))
else
print_endline str
let rec each_line ic =
fold_line !width (input_line ic);
each_line ic
let fold_file filename =
let infile = open_in filename in
try
each_line infile
with
End_of_file -> close_in infile
let () =
Arg.parse spec
(fun s -> filenames := s :: !filenames)
"Usage: fold [--width width] [--help] [--version] filename ...";
List.iter fold_file (List.rev !filenames)
^o^ >ocamlc -o fold.exe fold.ml
^o^ >fold --width 40 fold.ml
let version = "0.1"
let filenames = ref []
let width = ref 80
let spec = [("--width",
Arg.Int (fun n -> width :=
n),
"Set line width");
("--version",
Arg.Unit (fun () -> Printf
.printf "fold in OCaml ver.%s\n" version
),
"Display version")]
let rec fold_line n str =
let len = String.length str in
if len > n then
( print_endline (String.sub str 0 n)
;
(以下略)

練習問題 10.1

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~のp.215より。

UNIXの cat コマンドは,ファイル名の列を引数として,その内容を順次表示する(標準出力 に書き込む)ものです。これを OCaml で実装し,実行可能ファイルを作成しなさい。オプシ ョンに関しては少なくとも行番号を表示するための -n オプションを実装すること。

let version = "0.1"
let display_linenum = ref false
let filenames = ref []
let spec = [("-n",
Arg.Set display_linenum,
"Display line number.");
("-version",
Arg.Unit (fun () -> Printf.printf "cat in OCaml ver.%s\n" version),
"Display version.")]
(* print each lines *)
let rec output_file ic =
print_endline (input_line ic);
output_file ic
(* print each lines with line number *)
let rec output_file_n n ic =
Printf.printf "%5d %s\n" n (input_line ic);
output_file_n (n+1) ic
let cat_file filename =
let infile = open_in filename in
try
if !display_linenum then
output_file_n 1 infile
else
output_file infile;
with
End_of_file -> close_in infile
let () =
Arg.parse spec
(fun s -> filenames := s :: !filenames)
"Usage: cat [-n] [-help] [-version] filename ...";
List.iter cat_file (List.rev !filenames)

^o^ >ocamlc -o cat.exe cat.ml
^o^ >cat -n cat.ml
1 let version = "0.1"
2
3 let display_linenum = ref false
4
5 let filenames = ref []
6
7 let spec = [("-n",
8              Arg.Set display_linenum,
9              "Display line number.");
10             ("-version",
11              Arg.Unit (fun () -> Printf.printf "cat in OCaml ver.%s\n" ve
sion),
12              "Display version.")]
13
(以下略)

Problem 31

今日は Problem 31。

 

 cf. Project Euler – Problem 31
 cf. Life Goes On – 31問目

id:rst76さんのをちょっと改良して1pのコインがない場合にも対応できるようにしてみた。問題の解答には必要ないんだけど。

module Main (main) where

euler031 :: [Int] -> Int -> Int
euler031 (x:[]) m | m `mod` x == 0 = 1
                 | otherwise = 0
euler031 (x:xs) m = sum $ map (\n -> euler031 xs (m - x*n)) [0..(m `div` x)]

main :: IO ()
main = putStrLn $ show $ euler031 [200,100,50,20,10,5,2,1] 200
^o^ >runhaskell euler031.hs
73682

1pのコインがない場合:

*Main> euler031 [200,100,50,20,10,5,2] 200
1784

Problem 14

今日は Problem 14。

 cf. Project Euler – Problem 14

コラッツ問題の数列を求めるのは以前にやったのを流用。あとは力任せに…

module Main (main) where

collatz :: Int -> [Int]
collatz 1 = 1 : []
collatz n | n `mod` 2 == 0 = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)

euler014 :: Int -> [Int]
euler014 n = snd $ foldl g (0, []) $ map f [1..n]
  where
    f x = ((length.collatz) x, x)
    g (x,zs) (l,z) | x < l = (l, z:[])
                   | x == l = (x, z:zs)
                   | otherwise = (x, zs)

main :: IO ()
main = mapM_ (putStrLn.show) $ euler014 1000000

やったらあえなくスタックオーバーフローに。ありゃ。

^o^ >runhaskell euler014.hs
*** Exception: stack overflow

100,000までだったらうまくいったので間違ってはいないと思う。たぶん数列がすごく長くなる数があるんだろうな。再挑戦はまた今度。

あと,ついでに書いておくと,各数の数列にはおなじ部分列が何度も出現する。これを覚えておけば計算量を少なくできるんだけど,メモ化のやり方がわからない。

Problem 8

今日は Problem 8。

 cf. Project Euler – Problem 8

module Main (main) where

import Data.List
import Data.Char

euler008 :: [Char] -> Int
euler008 n = maximum $ map euler008' $ nums n
  where
    nums = filter (\x -> length x > 4) . map (take 5) . tails
    euler008' = foldl1 (*) . map digitToInt

main :: IO ()
main = do n <- getContents >>= return . concat . lines
          putStrLn $ show $ euler008 n
^o^ >runhaskell euler008.hs < euler008.txt
40824