flymakeでscalaの文法をリアルタイムにチェックする
前回のはおまけで、やりたかったのはむしろこっち。
flymakeがわからない人はこちらを参照。
(eval-when-compile (require 'cl)) (require 'flymake) (defvar flymake-scala-tmpdir "/tmp") (defvar flymake-scala-global-classpath ".") (push '(".+\\.scala$" flymake-scala-init) flymake-allowed-file-name-masks) (push '("^\\(.*\\):\\([0-9]+\\): error: \\(.*\\)$" 1 2 nil 3) flymake-err-line-patterns) (defun flymake-scala-string-join (sequence separator) (mapconcat #'identity sequence separator)) (defun flymake-scala-string-not-empty (str) (and (stringp str) (not (or (string-equal "" str) (string-match "^ +$" str))))) (defun flymake-scala-parent-dir (path) "return parent directory path of argument." (substring-no-properties (file-name-directory path) 0 -1)) (defun flymake-scala-find-target-file-dir (path target) (let* ((src (split-string (flymake-scala-parent-dir path) "/")) (paths (maplist #'(lambda (l) (flymake-scala-string-join (reverse l) "/")) (nreverse src)))) (loop for path in paths if (file-exists-p (concat path "/" target)) return path))) (defun flymake-scala-maven-build-cmd () (list "mvn" (list "-fn" "-Dmaven.compiler.showWarnings=true" "dependency:copy-dependencies" "scala:compile"))) (defun flymake-scala-build-cmd (target distdir classpath) (list "fsc" (list "-classpath" classpath "-d" distdir target))) (defun flymake-scala-init () (let ((dir (flymake-scala-find-target-file-dir buffer-file-name "pom.xml"))) (if (flymake-scala-string-not-empty dir) (progn (cd dir) (let ((distdir (loop for path in '("target" "build") if (file-exists-p path) return path))) (if (flymake-scala-string-not-empty distdir) (let* ((classes (concat distdir "/classes")) (dependency (concat distdir "/dependency")) (jars (directory-files dependency t "^[^\.]")) (classpath (flymake-scala-string-join (append (cons classes jars) flymake-scala-global-classpath) ":"))) (flymake-scala-build-cmd buffer-file-name classes classpath)) (flymake-scala-maven-build-cmd)))) (flymake-scala-build-cmd buffer-file-name flymake-scala-tmpdir flymake-scala-global-classpath)))) (defun flymake-scala-start-fsc-server () (with-temp-buffer (call-process-shell-command "fsc" nil nil))) (defun flymake-scala-maven-update () (interactive) (let ((dir (flymake-scala-find-target-file-dir buffer-file-name "pom.xml"))) (if (flymake-scala-string-not-empty dir) (progn (cd dir) (let* ((cmd (flymake-scala-maven-build-cmd)) (progname (car cmd)) (args (cadr cmd)) (buffname (format "*%s*" progname)) (buffer (get-buffer-create buffname))) (switch-to-buffer-other-window buffer) (start-process-shell-command progname buffer progname (flymake-scala-string-join args " ")))) (message "No pom.xml found")))) (add-hook 'scala-mode-hook (lambda () (flymake-scala-start-fsc-server) (flymake-mode-on)))
maven2のプロジェクトにも地味に対応。
pom.xmlを再帰的に探して存在する場合はmvn scala:compileを、
無い場合はfscをflymakeで実行させとります。
■参考にしたサイト
2009/10/04 18:00
mvnコマンドの実行が遅いので、二回目以降はfscを使うように修正。
後からjarなどを追加した場合は、
を実行してください。
2009/10/10 21:00
rails.elの関数を参照してしまっていたのを修正
anythingを使ってflymakeのエラー行を表示する
探してみても見あたら無かったので慣れないelispで書いてみたでござるの巻
(eval-when-compile (require 'cl)) (require 'flymake) (setq anything-c-source-flymake '((name . "Flymake") (init . (lambda () (setq anything-flymake-err-list (loop for err-info in flymake-err-info for err = (nth 1 err-info) append err)))) (candidates . (lambda () (mapcar (lambda (err) (let* ((text (flymake-ler-text err)) (line (flymake-ler-line err))) (cons (format "[%s] %s" line text) err))) anything-flymake-err-list))) (action . (("Goto line" . (lambda (candidate) (goto-line (flymake-ler-line candidate) anything-current-buffer))))))) (defun anything-flymake () (interactive) (something (list anything-c-source-flymake)))
M-x anything-flymake
でエラーの一覧を表示。
C-zでanythingのバッファを開いたままactionが実行出来るので、
一覧を表示させたままエラー行の表示できます。
ポーカーの勝敗判定
haskell入門中
■参考
http://www6.airnet.ne.jp/spade/poker/rule/yaku.html
import Data.List import Data.Maybe import Random data Suit = Spade | Heart | Diamond | Club deriving (Eq, Enum, Show) type Rank = Int data Card = Card Rank Suit deriving Show data Pair = Pair Rank Int deriving Show data Role = HighCard | OnePair | TwoPair | ThreeOfAKind | Straight | Flush | FullHouse | FourOfAKind | StraightFlush | RoyalFlush deriving (Eq, Ord, Show) data Hand = Hand Role [Rank] deriving Show run :: [Card] -> [Card] -> Ordering run p1 p2 = deal (analysis p1) (analysis p2) deal :: Hand -> Hand -> Ordering deal (Hand h1 r1) (Hand h2 r2) | h1 /= h2 = h2 `compare` h1 | otherwise = r2 `compare` r1 analysis :: [Card] -> Hand analysis cs = let rs = sortRank cs s = straight rs f = flash cs ps = pair rs hs = highcard rs in hand s f ps hs where sortRank :: [Card] -> [Rank] sortRank = sortRoyal . toRanks where toRanks = map $ \(Card r _) -> r sortRoyal rs | rs == [1, 2, 3, 4, 5] = rs | otherwise = sort $ map (\r -> if r == 1 then 14 else r) rs straight :: [Rank] -> Bool straight rs = all (== 1) $ zipWith (-) (tail rs) rs flash :: [Card] -> Bool flash = same . toSuits where toSuits = map $ \(Card _ s) -> s same (s:ss) = all (== s) ss pair :: [Rank] -> [Pair] pair = (map (\xs -> Pair (head xs) (length xs))) . (filter ((> 1) . length)) . group highcard :: [Rank] -> [Rank] highcard = concat . (filter ((== 1) . length)) . group hand :: Bool -> Bool -> [Pair] -> [Rank] -> Hand hand True True [ ] rs | rs == [10, 11, 12, 13, 14] = Hand RoyalFlush [] | otherwise = Hand StraightFlush [head rs] hand False False [(Pair r 4) ] rs = Hand FourOfAKind $ r:reverse rs hand False False [(Pair r2 2), (Pair r3 3)] _ = Hand FullHouse [r3, r2] hand False False [(Pair r3 3), (Pair r2 2)] _ = Hand FullHouse [r3, r2] hand False True [ ] rs = Hand Flush [head rs] hand True False [ ] rs = Hand Straight [head rs] hand False False [(Pair r 3) ] rs = Hand ThreeOfAKind $ r:reverse rs hand False False [(Pair r1 2), (Pair r2 2)] rs = Hand TwoPair $ r2:r1:reverse rs hand False False [(Pair r 2) ] rs = Hand OnePair $ r:reverse rs hand False False [ ] rs = Hand HighCard $ reverse rs
ランダムに対戦させてみる。
cards = [(Card r s) | r <- [1 .. 13], s <- [Spade .. Club]] main = do cards' <- getStdGen >>= (\g -> return $ shuffle g cards) mapM_ (\(p1, p2) -> poker p1 p2) $ oddEvenList $ splits 5 cards' where poker :: [Card] -> [Card] -> IO () poker p1 p2 = do print $ "p1 = " ++ (show p1) print $ " = " ++ (show $ analysis p1) print $ "p2 = " ++ (show p2) print $ " = " ++ (show $ analysis p2) print $ msg $ run p1 p2 where msg LT = "P1 Win!!" msg GT = "P1 Lose..." msg EQ = "even" splits :: Int -> [a] -> [[a]] splits n xs | length xs >= n = let (x, xs') = splitAt n xs in x : splits n xs' | otherwise = [] oddEvenList :: [a] -> [(a, a)] oddEvenList xs = zip (oddList xs) (evenList xs) where filterList :: ([a] -> Bool) -> [a] -> [a] filterList p [] = [] filterList p (x:xs) | p xs = x : filterList p xs | otherwise = filterList p xs oddList = filterList (odd . length) evenList = filterList (even . length) shuffle g [] = [] shuffle g xs = x : shuffle g' rest where (n, g') = randomR (0, length xs - 1) g (x, rest) = pick n xs pick :: Int -> [a] -> (a, [a]) pick n xs = let (ys, p:zs) = splitAt n xs in (p, ys++zs)
xmlのfolding(折り畳み)をする
たまには更新しろよってことでemacs小ネタ。
一万行のxmlファイルの修正依頼に涙がぶち切れそうになったので
emacsの折り畳みについてさらっと調べてみたら、hs-minor-modeなるものが標準で入ってた。
ということでsgmlモードでxmlの折り畳みをする設定。
ついでに標準のキーバインド(C-c @ C-c とか)が使いづらいので、
sgml-modeで空いてそうなC-c系列に変更。
(add-hook 'sgml-mode-hook '(lambda() (hs-minor-mode 1))) (add-to-list 'hs-special-modes-alist '(sgml-mode "<!--\\|<[^/>]>\\|<[^/][^>]*[^/]>" "" "<!--" sgml-skip-tag-forward nil)) ;; key bind (define-key sgml-mode-map (kbd "C-c C-o") 'hs-toggle-hiding) (define-key sgml-mode-map (kbd "C-c C-l") 'hs-hide-level) (define-key sgml-mode-map (kbd "C-c C-s") 'hs-show-all)
ここ最近インストールして便利だったソフト
Synergy
複数のパソコンでキーボードやマウスを共有するためのソフト。
Windows to Linuxだったり逆だったり。
クリップボードの共有もできて超便利。
入手先 : apt-get
xmonad
Haskellで書かれたタイル型のWindow Maneger。
キーボードでウィンドウのレイアウト切り替えたりランチャー起動したり。
キーボードマニア垂涎。
こいつのせいでGnome Doやら数多のソフトが御役御免になった。南無。
xmonad + emacs + vimperator + HHK Pro 無刻印
世界中の人間は皆敵みたいな環境ができた。
難点(利点?)は設定ファイルが.hs(Haskell)なとこ。
入手先 : apt-get
Dropbox
ローカルファイルと同じように使えるオンラインストレージサービス。
無料で使えるのは2Gまで。
指定のフォルダに変更が入ると勝手に同期とってくれる。
.zshrcやら.emacs.d/やらの設定ファイルをこいつに上げて、
homeフォルダからシンボルリンクを張れば複数パソコンの共有が完成。
ついでにシンボルリンク張る所と必要なパッケージ取得する所を、
shell化したら環境導入もめっちゃ楽になった。
入手先 : Dropbox - Simplify your life
どう書く?org#8053「島の数をカウントする」
お題
m×nの長方形のマス目のうちいくつかを黒く塗りつぶします。
このとき、白の島、黒の島がそれぞれいくつあるかをカウントしてください。ただし、2つのマスは、同色マスの上下左右の移動で移れるとき、
同じ島にあると定義します。例:
□■■□
□□■□
□■□□
□■■□
白の島は2つ
黒の島は2つ例:
□□□□
■□■□
□■□□
□□□□
白の島は1つ
黒の島は3つ
回答
object Q8053 { object Tile extends Enumeration { val White, Black, Fill = Value } import Tile._ def countIsland(str : String, target : Value) = { var data = parse(str) var result = 0 for (y <- 0 to data.length - 1; x <- 0 to data(y).length - 1) { if (data(y)(x) == target) { fill(data, y, x, target) result += 1 } } result } def parse(str : String) = { str.lines.toList.map(_.toList.map( x => if (x == '□') White else Black).toArray).toArray } def fill(data : Array[Array[Value]], y :Int, x :Int, target : Value):Unit = { if (y < 0 || y >= data.length || x < 0 || x >= data(y).length || data(y)(x) != target) { return } data(y)(x) = Fill fill(data, y-1, x, target) fill(data, y+1, x, target) fill(data, y, x-1, target) fill(data, y, x+1, target) } } object Main { val sample1 = """□■■□ |□□■□ |□■□□ |□■■□""".stripMargin val sample2 = """□□□□ |■□■□ |□■□□ |□□□□""".stripMargin def main(args : Array[String]) = { println(Q8053 countIsland(sample1, Q8053.Tile.White)) // 2 println(Q8053 countIsland(sample1, Q8053.Tile.Black)) // 2 println(Q8053 countIsland(sample2, Q8053.Tile.White)) // 1 println(Q8053 countIsland(sample2, Q8053.Tile.Black)) // 3 } }
すごくjavaっぽいです…。
完全に副作用無しで書こうして挫折した。
こういうのを関数型言語っぽく書くにはどうしたらいいんだろう。
うはwww Scala で Grass を実装してみたwwwwwwww
Scalaの勉強がてら ちょっと草植えときますね型言語 Grass を実装してみましたwwwwwww
今更感が今更だけど大自然の意志には逆らえないwwwwwww
_, ._
( ・ω・) んも〜
○={=}〇,
|:::::::::\, ', ´
、、、、し 、、、(((.@)wvwwWWwvwwWwwvwwwwWWWwwWw
事前目標
コード
class Grass { class CED(c :List[Insn], e :List[Value], d :List[CE]) { val code = c val env = e val dump = d } class CE(c :List[Insn], e :List[Value]) { val code = c val env = e } val ENV = List[Value](In, CharFn('w'), Succ, Out) val DUMP : List[CE] = List(new CE(Nil, Nil), new CE(List(App(1, 1)), Nil)) def run(str : String) : Unit = evalGrass(new CED(parse(str), ENV, DUMP)) def evalGrass(ced :CED) : Unit = { def loop(ced :CED) : CED = ced.code match { case head::tail => loop(eval(head, new CED(tail, ced.env, ced.dump))) case Nil => if (!ced.dump.isEmpty) { loop(new CED(ced.dump.last.code, ced.dump.last.env:::List(ced.env.last), ced.dump.slice(0, ced.dump.length-1))) } else { null } } loop(ced) } val PATTERN_ABS = "^(w+)(.*)".r val PATTERN_APP = "^(W+)(w+)(.*)".r def parse(src : String) : List[Insn] = { normalize(src).split("v").toList.flatMap(_ match { case PATTERN_ABS(x, y) => List(Abs(x.length, parseBody(y))) case PATTERN_APP(m, n, body) => App(m.length, n.length)::parseBody(body) case _ => throw new Exception("parse error") }) } def normalize(s : String) = { "[^wWv]".r.replaceAllIn( "\\A[^w]*".r.replaceFirstIn( s.replaceAll("w", "w"). replaceAll("W", "W"). replaceAll("v", "v"), ""), "") } def parseBody(src : String) : List[Insn] = { def _parseBody(src : String, code : List[Insn]) : List[Insn] = src match { case PATTERN_APP(m, n, body) => _parseBody(body, code:::List(App(m.length, n.length))) case _ => code } _parseBody(src, Nil) } abstract class Insn case class App(m :Int, n :Int) extends Insn case class Abs(n :Int, code :List[Insn]) extends Insn def eval(insn :Insn, ced :CED) : CED = insn match { case App(m, n) => app(ced.env(ced.env.length - m), ced.env(ced.env.length - n), ced) case Abs(1, c) => new CED(ced.code, ced.env:::List(Fn(c, ced.env)), ced.dump) case Abs(n, c) => new CED(ced.code, ced.env:::List(Fn(List(Abs(n - 1, c)), ced.env)), ced.dump) } abstract class Value case class Fn(code : List[Insn], env : List[Value]) extends Value { override def toString() :String = "Fn" } case class CharFn(char : Char) extends Value case object Succ extends Value case object Out extends Value case object In extends Value val ChurchTrue = Fn(List(Abs(1, List(App(3, 2)))), List(Fn(Nil, Nil))) val ChurchFalse = Fn(List(Abs(1, Nil)), Nil) def app(v :Value, arg :Value, ced :CED) : CED = v match { case Fn(c, e) => new CED(c, e:::List(arg), ced.dump:::List(new CE(ced.code, ced.env))) case CharFn(char) => new CED(ced.code, ced.env:::List(if (char == getChar(arg)) ChurchTrue else ChurchFalse), ced.dump) case Succ => new CED(ced.code, ced.env:::List(CharFn(((getChar(arg) + 1) % 256).asInstanceOf[Char])), ced.dump) case Out => System.out.print(getChar(arg)) System.out.flush() new CED(ced.code, ced.env:::List(arg), ced.dump) case In => new CED(ced.code, ced.env:::List(CharFn(System.in.read().asInstanceOf[Char])), ced.dump) } def getChar(v :Value) : Char = v match { case CharFn(char) => char case _ => throw new Exception("eval error at getChar") } }
100行ぐらいに収まりました。
実行例
object Main { def main(args : Array[String]) = { var grass = new Grass() // w grass.run("wWWwwww") println() // x grass.run("wWWWwwwwWWWw") println() // ww grass.run("wwWWwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWWwwwWwwwwWwwwwwwWwwwwwwwww") println() // Hello, world! grass.run("wvwWwwwwWwwwwwwWWWWWwWWWWWwwwwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWW" + "wWwwvwwWWwvwWWWwwWWWWWwwwWwwWWWWWWwWWWWWWWwWWWWwWWWWWwWWWWWW" + "wWWWWWWWWWWWWWWwwwwwwwwWwWwWWWwwWWWWwwwwwwwWWWWWwwwwwwwWWWWW" + "WwwwwwwwWWWWWWWWWWWWWWWWWWWWWwwwwwwwwwwwwwwwwwwwwwWwwwwwwwww" + "wwwwwwwwwwwWwwwwwwwwwwwwwWwwwwwwWWwwwwwwWWWwwwwwwWWWWWWwwwww" + "wwwwwwwwwwwwwwwWwwwwwwwwwwWWwwwwWWWwwwwWWWWwWWWWWwwwwwwwwwww" + "wwwwwwwWWWWWWWWWWWwWwwwWWwWWWwWWWWwWWWWWWWWWWWWWWWWWwwwwwwww" + "wwwwwwwwwWwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWwwwwwwwwwww" + "WWwwwwwwwwwwwWWWwwwwwwwWWWWwWWWWWwwwwwwwwWWWWWWwwwwwwwwwwwww" + "wwwwwwwwWWWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWWWWwwwwwwww" + "WwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWwwwwwwwwwwwwwWWWwwwwwwwww" + "wwwwWWWWwwwwwwwwWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWwwwwwww" + "wwwwwwwwwwwwwwwwww") } }
芝が広がりんぐwwwwwww