F#のべき乗計算
現在F#の勉強を始めたところで、基礎的なところをぼちぼち習得している段階です。
演算子の話なんですが、F#にはOCamlの系譜だからなのか**
演算子(べき乗)があります。
RubyやPythonなど、関数型の血を引いたいくつかの言語にも備わっている珍しくもない演算子なんですが、
なんとこの演算子、F#においては浮動小数点型でしか使えないのです…。
(コンパイルするとMath.Pow : float * float -> float
になるようなので、当然と言えば当然ですね…)
追記: コンパイル後に Math.Pow
になるのはインライン関数だからで、実際は Pow
静的メソッドを持つ任意の型に対して使える模様。
つまり BigInteger
とかでも使えます。
なので整数計算で**
演算子を使用したい場合は、
let i = 2 ** 3 // ここでコンパイルエラー printfn "%i" i
ではダメで、
let i = 2.0 ** 3.0 |> int printfn "%i" i // 8
などとしなくてはならず、少々面倒くさいです。
どうしてもという場合にはpown
関数がありますが、あくまで関数なので演算子のように中置はできない模様。
let i = pown 2 3 printfn "%i" i // 8 // パイプ演算子を使うと中置っぽくなるが、アホっぽい let i2 = 2 |> pown <| 3 printfn "%i" i2 // 8
ぐぬぬ。
全てのフレームを対象にするには
某大手工業系企業の新規開発プロジェクトに参画しているのですが、非常に悲しいことに社内ポータルが未だにフレームを使用したサイトなのです。
フレームを使うと容易にペインで分けたサイトを構築できるため、実用重視のエンタープライズ界隈で重宝されるのはよく分かります。
ただ、フレーム*1を使うと、ブックマークレットを作ろうと思ったときにそのままではトップレベルのウィンドウにしか効力を発揮しません。
埋め込まれているフレームのソースURLがトップレベルのウィンドウと同じドメインに属しているのであれば*2、以下のようなコードを使うことで全フレームに対して操作することができます。
// for IE9+ (function loop(win) { return Array.prototype.reduce.call(win, function(p, c) { return p.concat(loop(c.window)); }, [win]); })(window) .forEach(function(window) { var document; try { document = window.document; } catch(e) { return; } /* code here */ });
// compressed (function l(w){return [].reduce.call(w,function(p,c){return p.concat(l(c.window))},[w])})(window).forEach(function(w){try{var d=w.document}catch(e){return}/* code here */})
*1:<iframe>も同様です。
*2:Same-Origin PolicyはWebにおける重要な概念です。
最近 Nemerle がマイブームです
私自身は最近知ったのですが、実は以前からある言語っぽいですね。
C#によく似た構文を数多く持ち、関数型言語によく見られる機能(パターンマッチングとかタプルとか)を言語レベルで実装しているのが特徴です。
型を静的にチェックできる強力なマクロもあって、かなり自由度の高いコードが書けるようです。
foreach
文なんかもマクロで書かれているそうです。
あと#pragma indent
ディレクティブを宣言することでPythonやF#, CoffeeScript, Haml, SASSなどで馴染みのある「インデントが意味を持つ」書き方ができます。
自分はまだそこまで使いこなせてないですが、書いていてすごく楽しいです。
知名度もそれほどなくコミュニティもあまり活発ではないようですが、C#もF#も好きって人には向いているんではないでしょうか。
例えば、以下は拙い知識で書いたフィボナッチ数列を求めるコードです。 gist.github.com
これはC#で書くと大体こんなような感じです。
using static System.Console; using System.Numerics; static class Program { static void Main() { Action<int> fib = null; fib = n => { WriteLine("{0,8} : {1}", n, Fibonacci(n)); if (n % 10 == 0) ReadLine(); fib(n + 1); }; fib(1); } private static BigInteger Fibonacci(int n) { var a = BigInteger.Zero; var b = BigInteger.One; foreach (int i in Enumerable.Range(0, 31).Reverse()) { BigInteger c = a; a = a * (b * 2 - a); b = c * c + b * b; if ((((uint)n >> i) & 1) != 0) { c = a; a = b; b = c + b; } } return a; } }
これだけだと正直何がいいのか伝わらない自覚はあります。
Nemerleらしい箇所はタプルでの多重代入とdef
を使った型推論くらい…。
match (expr)
はdef
の直下やforeach
の直下で省略できるため、
// A(文字コード: 65)からz(同: 122)までの大文字で、かつ偶数番目に出現する文字のみを出力 foreach (c in $['A' .. 'z'] with index) { | x when char.IsUpper(x) && index % 2 == 1 => Write(c) | _ => () } WriteLine(); // 冗長に書くとこう foreach (c in $['A' .. 'z'] with index) { match (c) { | x when char.IsUpper(x) && index % 2 == 1 => Write(c) | _ => () } }
こんな感じでforeach
からのパターンマッチとかやるとちょっとはメリットが見えてくるかもしれません。
分かりやすさのためにあえてc
とx
と変数名を変えましたが、Nemerleはスコープが異なる場合は変数名のオーバーライドが可能なので、
// 上のコードで、4行目をこう書いても意味は同じ | c when char.IsUpper(c) && index % 2 == 1 => Write(c)
です。
こんなコードも書けます。
Main() : void { def n = 10; def somefunc(n) { $[n ** 3, n in [1 .. n]] } def listToString(list) { "[" + string.Join(", ", list) + "]" } def list = somefunc(n); WriteLine(listToString(list)); }
n
が何を指しているのか、コンテキストが分かりづらいのでほどほどにするのがよさげですね。
個人的には自由度が上がったC#の延長、みたいな感じに捉えています。
地味にC# 7.0から対応の2進数リテラル(0b1011
みたいなの)もとっくのとうに実装済みだったり、便利です。
リンク化スクリプト
かねてからHatena::Let で公開 *1 していて、個人的にもかなり使っているスクリプトをGreaseMonkey用に書き直したのでそれも公開してみます。
https://gist.github.com/htsign/5eed5473a9e75c7c45f3a5571d7d0803/raw/convertTextToLink.user.js
GreaseMonkey用っていうか単にES2015で書き直しただけで、特別GreaseMonkeyには依存していませんが。
せっかくなのでGreaseMonkey版はMutationObserver
による追加ノードの監視機能も付けました。
Hatena::Letの方(以下、ブックマークレット版)にはこの機能は持たせていません。
対象となるブラウザの範囲にIEも入るからです。
新しいノードに適用する為には都度実行してやれば済む話で、別にそんなに手間なわけでもありませんし。
一応Mutation Events
(document.addEventListener("DOMNodeInserted", ...
みたいなやつ)はIE9から対応していますが、これは既に非推奨となった技術なので積極的に採用するつもりはないです。
場合分けめんどいですしね(本音)
NodeIterator
で探索しているのでそれなりに速いと思いますが、そもそもの計算量の時点でたかが知れてるのでアレです。
注意点として、テキストに対して要素を追加する(DOMに破壊的変更を加える)為、DOMの構造に依存した外部コードがある場合には不具合の原因となる可能性があります。
他の人がエントリに書いてた仕分けbatが冗長だったのでvbsにした
本当はC#とかでパパッと書いてしまうのが楽だけど、元ネタがバッチファイルなのでWindows標準で動くスクリプトという点でWSHを選びました。*1
PowerShellはローカルで気軽に動かすためにポリシーを変更する必要があるので却下。
Option Explicit Const ForWriting = 2 Const TristateFalse = 0 Dim wsh, fso Set wsh = WScript.CreateObject("WScript.Shell") Set fso = WScript.CreateObject("Scripting.FileSystemObject") wsh.CurrentDirectory = fso.GetParentFolderName(WScript.ScriptFullName) Dim logfile, folder, file Set logfile = fso.OpenTextFile("imageFiltering.log", ForWriting, True, TristateFalse) Set folder = fso.GetFolder(wsh.CurrentDirectory) For Each file In folder.Files Dim name, index name = file.Name index = InStrRev(name, ".") If index > 0 Then Dim ext ext = Mid(name, index + 1) Select Case LCase(ext) Case "jpg", "jpeg", "gif", "png" Call Move(name) End Select End If Next Function Move(filename) Dim re, ms, m Set re = New RegExp re.Pattern = "モデル\:([^]]+)" Set ms = re.Execute(filename) For Each m In ms Dim matched, models, model matched = m.SubMatches(0) models = Split(matched) For Each model In models If Not fso.FolderExists(model) Then fso.CreateFolder model End If logfile.WriteLine "【" & filename & "】を【" & model & "】フォルダにコピー" fso.CopyFile filename, fso.BuildPath(model, filename) Next logfile.WriteLine "【" & filename & "】を削除" fso.DeleteFile filename Next Set ms = Nothing Set re = Nothing End Function logfile.Close Set logfile = Nothing Set folder = Nothing Set fso = Nothing Set wsh = Nothing
スクリプトをShift-JISで保存しないと正規表現エンジンが正しく動作しません。
あと例外処理とかなにもしてないのでその辺はよしなに。
書いてる途中でいっそファイルのダウンロードも自動化しようかとも思ったけどめんどくさいのでやめました。