予約語

break else new var
case finally return void
chatch for switch while
continue function this with
default if throw
delete in try
do instanceof tpeof

将来のために予約されている語もある:

abstract enum int short
boolean export interface static
bye extends long super
char final native synchronized
class float package throws
const goto private transient
debugger implements protected volatile
double import public

演算子

当たり前のものは省略。

  • インクリメント(++)/デクリメント(–)。前置と後置。
  • 論理演算子: !/&&/||。not/and/or はない。
  • ビット演算子: &(論理積)/|(論理和)/^(排他的論理和)
  • シフト演算子: <<(左シフト)/>>(右算術シフト)/>>>(右論理シフト)。右算術シフトは,符号ビットは保存されるようにシフトされる。
var x = 10;
x >> 1;       // -5
x >>> 1;      // 2147483643
  • typeof演算子:値の型を調べる。

’===’ と ’==’

  • ‘===’ は型も含めて同一でなければ true にならない。
  • ‘==’ は型が違っても構わない。たとえば,数値の 10 と文字列の “10” が true になる。
var n = 10;
var s = "10";

with(document) {
    write("n = ", n, " ; type: ", typeof n, "<br>");
    write("s = ", s, " ; type: ", typeof s, "<br>");
    write("n === s : ", n === s, "<br>");      // false
    write("n == s : ", n == s, "<br>");        // true
}

故あって JavaScript に手を出す

基本事項。

  • 大文字と小文字を区別
  • ステートメントの終わりにはセミコロン;
  • // 行末までコメント
  • /* 複数行のコメント */
  • スクリプトは script タグで囲む。
  • JavaScript を認識できないブラウザのために,<!– と //–> で囲む(HTMLのコメント扱い)。
<script language="javascript" type="text/javascript">
<!--
    document.write("<hr>");
     document.write("<h1>This is JavaScirpt.<h1>");
     document.write("<hr>");
//-->
</script>
  • 関数の定義などは head エレメント内,出力などはその場所に書くのが一般的。
  • 外部ファイルにしたスクリプトは script エレメントの src 属性で指定する。
<script type="text/javascript" src="ext.js"></script>

文字列を空白で区切る

テキストファイルから入力を受け付ける時にはよく使う。あとはカンマ区切りなんかも。

import Data.Char

splitBy :: (a -> Bool) -> [a] -> [[a]]
splitBy p [] = []
splitBy p xs = a : (splitBy p $ dropWhile p $ b)
  where
    (a, b) = break p xs

splitBySpace :: String -> [String]
splitBySpace = splitBy isSpace
*Main> splitBySpace "a b c"
["a","b","c"]
*Main> splitBySpace " a b c "
["","a","b","c"]

正規表現(Text.Regex)を使えばもっとシンプルに書ける。

import Text.Regex

splitBySpace' :: String -> [String]
splitBySpace' = splitRegex (mkRegex " +")
*Main> splitBySpace' "a b c"
["a","b","c"]
*Main> splitBySpace' " a b c "
["","a","b","c",""]

……けど,ちょっと動作が違うな。
ちなみに Ruby の String#split は上の splitBySpace と同じ動作。

D:\>irb --simple-prompt
>> "a b c".split(/ +/)
=> ["a", "b", "c"]
>> " a b c ".split(/ +/)
=> ["", "a", "b", "c"]

リストによる正方行列(つづき)

cf. 今日の一行 – リストによる正方行列処理

週をまたいでしまった。解答例もでてるけど。

問題3。これも内包表記で。

boxing :: [[a]] -> [[a]]
boxing m = [[m!!x!!y| x <- [0..l1], y <- [0..l1], x`div`l2 == i, y`div`l2 == j] | i <- [0..l3], j <- [0..l3]]
  where
    l1 = length m - 1
    l2 = (floor . sqrt . fromIntegral . length) m
    l3 = l2 -1

行列のサイズから n を求めるとこで型が合わずにはまった(sqrt(Floating a) => a -> a,必要なのは Int)。結局 floor を使った。

パターンの回転

パソコン甲子園というのを見つけた。
プログラミング部門の問題が公開されてるので(↓)ちょっとやってみよう。

正方行列つながりってことで問題01。

8文字×8行のパターンを右回りに90度、180度、270度回転させて出力し終了するプログラムを作成してください。

rotateMatrixR で右に90度回転させる。左に回転させる rotateMatrixL があるのは,勘違いしてさきに書いちゃったから。でも考えると右回転はちょっと面倒そうだな。これで正解かも。
main は手抜き。美しくない。

module Main (main) where

main :: IO ()
main = do cs <- getContents >>= return . lines
          putStrLn "90"
          showMatrix $ rotateMatrixR cs
          putStrLn "180"
          showMatrix $ rotateMatrixR $ rotateMatrixR cs
          putStrLn "270"
          showMatrix $ rotateMatrixR $ rotateMatrixR $ rotateMatrixR cs

rotateMatrixL :: [[a]] -> [[a]]
rotateMatrixL [xs] = [[x]| x <- reverse xs]
rotateMatrixL (xs:xss) = zipWith (:) (reverse xs) (rotateMatrixL xss)

rotateMatrixR :: [[a]] -> [[a]]
rotateMatrixR = reverse . rotateMatrixL . reverse

showMatrix :: [String] -> IO ()
showMatrix = putStr . unlines

実行例。

D:\>type input01.txt
#*******
#*******
#*******
#*******
#*******
#*******
#*******
########
D:\>runhaskell problem01.hs < input01.txt
90
########
#*******
#*******
#*******
#*******
#*******
#*******
#*******
180
########
*******#
*******#
*******#
*******#
*******#
*******#
*******#
270
*******#
*******#
*******#
*******#
*******#
*******#
*******#
########

追記:
右回転の方が簡単だった……orz

rotateMatrixR' :: [[a]] -> [[a]]
rotateMatrixR' = transpose . reverse
*Main> showMatrix sampleMatrix
#*******
#*******
#*******
#*******
#*******
#*******
#*******
########
*Main> showMatrix $ rotateMatrixR' sampleMatrix
########
#*******
#*******
#*******
#*******
#*******
#*******
#*******
*Main> showMatrix $ rotateMatrixR' $ rotateMatrixR' sampleMatrix
########
*******#
*******#
*******#
*******#
*******#
*******#
*******#

さらに追記:
ちがう!左回転も同じくらい簡単だ。

rotateMatrixL' :: [[a]] -> [[a]]
rotateMatrixL' = reverse . transpose

リストによる正方行列

cf. 今日の一行 – リストによる正方行列処理

問題1。

matrix n = [[x+(n^2*y) | x <- [1..n^2]] | y <- [0..n^2-1]]
*Main> matrix 2
[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
*Main> matrix 3
[[1,2,3,4,5,6,7,8,9],[10,11,12,13,14,15,16,17,18],[19,20,21,22,23,24,25,26,27],[
28,29,30,31,32,33,34,35,36],[37,38,39,40,41,42,43,44,45],[46,47,48,49,50,51,52,5
3,54],[55,56,57,58,59,60,61,62,63],[64,65,66,67,68,69,70,71,72],[73,74,75,76,77,
78,79,80,81]]

問題2。
Data.Listtranspose そのままでは芸がないので。

transpose' m = [[m!!x!!y| x <- [0..l]] | y <- [0..l]]
  where
    l = length m - 1
*Main> transpose' $ matrix 2
[[1,5,9,13],[2,6,10,14],[3,7,11,15],[4,8,12,16]]

問題3はあとで。

追記:
問題2の別解。foldr を使う。これなら正方行列でなくてもOK。

transpose'2 m = foldr (\a b -> zipWith (:) a b) (replicate (length m) []) m
*Main> transpose'2 $ matrix 2
[[1,5,9,13],[2,6,10,14],[3,7,11,15],[4,8,12,16]]

クラスはよくてもモジュールは?

いままで気にしたことなんて無かったけど……

cf. Matzにっき – jijixi’s diary – Ruby の文法的欠陥

cf. じじぃの日記、ツッコミ可 – Ruby の文法的欠陥

jijixiさんのいう”欠陥”(というと言いすぎのような気もする,といっているけど)というのは

『新しいクラスを作ってるつもりで、知らないうちに既存のクラスを上書きする可能性がある』

で,これに対するまつもとさんの対策が

* ちゃんと名前空間を分離する

* クラスを定義する時にはスーパークラスを明示する

2つ目の方は,クラスを定義するときに指定したスーパークラスが合わないとエラーになるってことだな。

D:\>irb
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> class Bar; end
=> nil
irb(main):003:0> class Baz < Foo; end
=> nil
irb(main):004:0> class Baz < Bar; end
TypeError: superclass mismatch for class Baz
from (irb):4
from :0

そうは言っても class Foo < Object って書いてるのは見たこと無いけど。

さて,クラスはいいとしてもモジュールはどうだろう。

スーパークラスの明示みたいなものはないし,トップレベルで定義されたモジュールでは名前空間の分離もできない。

……ってことは,気をつけるしかないのか。

ちなみに,素の状態で定義されているモジュールは

D:\>type modules.rb
ObjectSpace.each_object(Object){|o| puts o.name if o.class == Module}
D:\>ruby modules.rb
Marshal
ObjectSpace
GC
Math
Process::Sys
Process::GID
Process::UID
Process
Signal
File::Constants
FileTest
Errno
Precision
Enumerable
Comparable
Kernel

意外に少ない。