「プログラミング in OCaml」をF#で(5)

第七章例外処理。意外と普通。というか、他の言語でも、例外の型で処理を振り分ける仕組みが見た目パターンマッチングっぽい。練習問題も少ない……。

  • P145。fsi.exe(F#の対話実行環境)だと、raiseした時の出力が全然違う。どういう意味なのかわからない……。
> raise Not_found;;
stdin(0,0): error: FS0030: Value restriction. Type inference has inferred the signature
        val it : '_a
Either define 'it' as a simple data term, make it a function, or add a type constraint to instantiate the type parameters.
  • P145。例外周りはOCamlと結構違うらしく、FS0062警告が出まくり。Division_by_zero > System.DivideByZeroException、Invalid_argument > InvalidArgument などなど。
  • P146。findの実行結果なんか変なので調べたら、Not_foundの実体はSystem.IndexOutOfRangeExceptionみたいだった。それなら、Division_by_zeroの代わりにSystem.DivideByZeroExceptionを使え、というのと同様の警告が出ても良さそうだけど……
  • 上の件。Invalid_argument > InvalidArgumentは、字面が違うだけで、同じように使える。
> InvalidArgument "0";;
val it : exn = InvalidArgumentException ()
  • しかし、Division_by_zero > System.DivideByZeroExceptionはそうではない。System.DivideByZeroException;;にすると、型名だかコンストラクタだかの使い方がおかしいので、newをつけろ、みたいなエラーが出る。newをつけると同じ感じになる。同じ感じでもないか……。まぁでもraiseできる。
> new System.DivideByZeroException();;
val it : System.DivideByZeroException
= System.DivideByZeroException: 0 で除算しようとしました。 {Data = dict [];
                                                HelpLink = null;
                                                InnerException = null;
                                                Message = "0 で除算しようとしました。";
                                                Source = null;
                                                StackTrace = null;
                                                TargetSite = null;}
  • InvalidArgumentExceptionのコンストラクタにはF#の例外コンストラクタであるInvalidArgumentが割り当てられているけど、System.DivideByZeroExceptionのコンストラクタにはF#の例外コンストラクタが割り当てられていない、ような感じに見えるんだけど、どうなんだろうか。ついでに、raise (new System.DivideByZeroException()) とかした時のcatchの仕方がわからない……
  • sampleディレクトリを漁っていたら、
        with 
            | :? Sockets.SocketException 
            | :? System.IO.IOException -> 
  • こんな感じで、判別できるみたいだった。
  • 練習問題は全部できたと思うので省略
  • 追記:prim-types.fsをみてたら
        [<ReflectedDefinition>]
        let failwith s = raise (Failure(s))
        [<ReflectedDefinition>]
        let invalid_arg s = raise (InvalidArgument(s))
        [<ReflectedDefinition>]
        let invalid_op s = raise (System.InvalidOperationException(s))
        [<ReflectedDefinition>]
        let not_found() = raise (new System.IndexOutOfRangeException())
  • prim-types.fsiに
    // F#-specific Exceptions

    exception Failure of string
    exception InvalidArgument of string
    exception AssertionFailure of string * int * int
    exception MatchFailure of string * int * int
        /// Throw a 'FailureException' exception
        val failwith : string -> 'a 
        /// Throw an 'InvalidArgumentException' exception
        val invalid_arg : string -> 'a 
        /// Throw an 'InvalidOperationException' exception
        val invalid_op : string -> 'a 
        /// Throw an 'IndexOutOfRangeException' exception
        val not_found : unit -> 'a 
  • とか書いてあったので、まぁなんかよくわからないけど、これらが特別に設定してあるということなんだろうな、と理解した。