ラベル の投稿を表示しています。 すべての投稿を表示
ラベル の投稿を表示しています。 すべての投稿を表示

2012年4月6日金曜日

Emacs Lisp のバッファとミニバッファ, エコーエリア

1. バッファ

テキストファイルを Emacs で開くと、内容はバッファに存在する。

Buffers - GNU Emacs Manual

The text you are editing in Emacs resides in an object called a buffer. …

Each buffer has a unique name, which can be of any length. …

At any time, one and only one buffer is current.

バッファは、Lisp オブジェクト。編集できるテキストを含んでいる。

Buffers - GNU Emacs Lisp Reference Manual

A buffer is a Lisp object containing text to be edited. … While several buffers may exist at one time, only one buffer is designated the current buffer at any time. Most editing commands act on the contents of the current buffer. …

バッファは複数存在する。編集用のコマンドが作用する対象は、カレントバッファと呼ばれる。

*scratch* バッファで

(current-buffer)

を評価すると、

#<buffer *scratch*>

#< … > という形式で表示される理由は、バッファそのものを、人間が読み取れる形式で表す適切な表現がないため。

Printed Representation - GNU Emacs Lisp Reference Manual によると、

In most cases, an object's printed representation is also a read syntax for the object. However, some types have no read syntax, since it does not make sense to enter objects of these types as constants in a Lisp program. These objects are printed in hash notation, which consists of the characters ‘#<’, a descriptive string (typically the type name followed by the name of the object), and a closing ‘>’.

 

バッファの型

Lisp オブジェクトは、Lisp プログラムが操作する対象であるデータ。全てのオブジェクトは、型を持つ。

Lisp Data Types - GNU Emacs Lisp Reference Manual

A Lisp object is a piece of data used and manipulated by Lisp programs. …

Every object belongs to at least one type. Objects of the same type have similar structures and may usually be used in the same contexts.

バッファは、Editing Types の一つに挙げられている。

Editing Types - GNU Emacs Lisp Reference Manual

Buffer Type: The basic object of editing.

バッファの型を確認するには、type-of 関数を用いる。

Type Predicates - GNU Emacs Lisp Reference Manual

The most general way to check the type of an object is to call the function type-of. …

— Function: type-of object

This function returns a symbol naming the primitive type of object.

(type-of (current-buffer))

を評価した結果は、

buffer

と表示される

 

*scratch* バッファ

Emacs を起動すると存在する *scratch* バッファについては、以下を参照。

Startup Summary - GNU Emacs Lisp Reference Manual

  • If the buffer ‘*scratch*’ exists and is still in Fundamental mode (as it should be by default), it sets its major mode according to initial-major-mode.
  • Auto Major Mode - GNU Emacs Lisp Reference Manual

    — User Option: initial-major-mode

    The value of this variable determines the major mode of the initial ‘*scratch*’ buffer. The value should be a symbol that is a major mode command. The default value is lisp-interaction-mode.

     

    2. ミニバッファ

    文字列を置換するときに使う、query-replace コマンドは、ミニバッファを使う。

    query-replace コマンドを実行すると、検索する単語と、置換する単語の入力が促される。その際、入力した内容は、通常のバッファと同じように、編集用のコマンドを適用できる。

    query-replace 関数のプロンプトは、エコーエリアと同じ場所に表示される。ミニバッファは、最後にコロンが表示されることが多い。渡した値は、関数の引数となる。

    Minibuffer - GNU Emacs Manual

    The minibuffer is where Emacs commands read complicated arguments, such as file names, buffer names, Emacs command names, or Lisp expressions. We call it the “minibuffer” because it's a special-purpose buffer with a small amount of screen space. You can use the usual Emacs editing commands in the minibuffer to edit the argument text.

    When the minibuffer is in use, it appears in the echo area, with a cursor. The minibuffer display starts with a prompt in a distinct color, usually ending with a colon. The prompt states what kind of input is expected, and how it will be used.

    エコーエリアは、エラーメッセージや、message 関数による出力内容が表示される。

    The Echo Area - GNU Emacs Lisp Reference Manual

    The echo area is used for displaying error messages (see Errors), for messages made with the message primitive, and for echoing keystrokes. It is not the same as the minibuffer, despite the fact that the minibuffer appears (when active) in the same place on the screen as the echo area.

    2009年5月18日月曜日

    Haskell のモジュールの階層化と、型クラス - パラメータ多相とアドホック多相

    0. 目次

    • 1. 同じ名前のフィールドラベルを持つ型を定義したい
    • 2. モジュールを分割し、階層化する
    • 3. 型の意味
    • 4. 型クラスの役割
    • 5. パラメータ多相と、アドホック多相
    • 6. 多相性とオブジェクト指向
    • 7. 演算子の意味
    • 8. 継承とジェネリクス
    • 9. Ad hoc の意味
    • 10. 型クラスの定義と、インスタンス化
    • 11. 余談: モジュールに分けない場合

     

    1. 同じ名前のフィールドラベルを持つ型を定義したい

    2 つの型が、類似している場合、フィールド名に同じ名前を使いたい。

    例えば、「名前」と「年齢」を持つ、「犬」型を定義する。

    このとき、フィールドラベルを使うなら、

    data Dog = Dog {name :: String, age :: Int} deriving Show

    「犬」型と同様のフィールドを持つ、「猫」型も定義。

    data Cat = Cat {name :: String, age :: Int} deriving Show

    しかし、同一モジュール (ここでは Main モジュール) で、同じフィールド名を持つ型を定義すると、エラーが発生する。 (+_+)

    Multiple declarations of `Main.name'
    ...
    Multiple declarations of `Main.age'
    ...

    理由は、3.15 フィールドラベルをもつデータ型3.15.1 フィールドの選択 によると、、

    フィールド名は選択子関数として使用する。変数として使用するときは、 フィールド名はオブジェクトからそのフィールドを取り出す関数として働く。 選択子はトップレベルの束縛なので局所変数によって覆い隠される。しかし、 同じ名前の他のトップレベルの束縛とは衝突することは出来ない。…

    (太字は引用者による)

    フィールド名は、単なる名前ではなく、フィールドの値を返す関数。名前空間は、トップレベルに所属するので、代数的データ型の中に書いているように見えても、バッティングに注意が必要ということ。

    つまり、以下のように、フィールドラベルは「関数」となるので、同じ名前の関数を二つ作れない。

    *Main> name $ Dog "pochi" 3
    "pochi"

     

    2. モジュールを分割し、階層化する

    では、同じフィールド名を持つ、異なる型を定義したい場合、どうすればいいのだろう?

    2.2.1. Modules vs. filenames によると、

    How does GHC find the filename which contains module M? Answer: it looks for the file M.hs, or M.lhs.

    GHC の場合、各々の型を別モジュールに定義し、別ファイルに含めるということ。

    つまり、先ほどの例の場合、「犬」と「猫」型に対応したモジュールを作成し、それぞれのファイルに記述すれば良い。

    説明に従い、最初に、「犬」型を ファイル Dog.hs に定義。

    module Dog where
        data Dog = Dog {name :: String, age :: Int} deriving Show

    ところで、GHC ではモジュールを階層化できる。

    The Glorious Glasgow Haskell Compilation System User's Guide, Version 6.10.25.6.1. Haskell source files によると、

    Usually, the file should be named after the module name, replacing dots in the module name by directory separators. For example, on a Unix system, the module A.B.C should be placed in the file A/B/C.hs, relative to some base directory.

    モジュールのベースとなるディレクトリを想定し、そこからの相対位置で、モジュール名が決まる。モジュール名は、モジュールを配置したディレクトリの階層に対応させ、`.’ により階層化していることを示すということ。

    例えば、先ほどの「猫」型をやめ、「三毛猫」型を Cat 階層に作りたい。この場合、

    1. Cat ディレクトリを作成し、
    2. 下記のモジュールを Mike.hs に記述し、Cat ディレクトリに配置。
    3. その際、モジュール名は、モジュールを配置したディレクトリに対応させるために Cat.Mike とする。
    module Cat.Mike where
        data Mike = Mike {name :: String, age :: Int}

    全体では、以下のようにファイルを配置する。

    Dog.hs
    Cat
    -- Mike.hs

    ただし、メインモジュールにおいて、フィールドラベルを用いて「名前」を表示したい場合、関数名 (フィールドラベル) をモジュール名で修飾しなくてはならない。

    import Dog
    import Cat.Mike
    main = do print $ Dog.name $ Dog "pochi" 3
              print $ Cat.Mike.name $ Mike "tama" 2

    できることなら、関数を適用するとき、モジュール名で修飾せず、シンプルに name と書きたい。

    そのためには、「型クラス」を使い、関数のオーバーロードを行う必要がある。

     

    3. 型の意味

    その前に、「型」について整理しておく。

    データベース実践講義」の「2.3 型とは」(p34) によると、

    型とはいったい何か。基本的には、値の名前付き有限集合である。…

    すべての型が、その型の値もしくは変数に作用する演算子の連想集合を持つ …

    Data type - Wikipedia, the free encyclopedia には、

    In a broad sense, a data type defines a set of values and the allowable operations on those values.

    つまり、「型」とは

    1. 値の集合と、
    2. その値に対する、操作が定義されたもの。

    上記より、オブジェクト指向における「クラス」を連想した。なぜなら、

    1. 「値」に相当するインスタンスと、
    2. 「操作」に相当するメソッドを持つため。

    Data type - Wikipedia には、型 (データ型) と呼ばれるものには、いくつか種類があることが示されている。

    上記データ型の違いの一例を挙げると、オブジェクト型では、内部状態を持つのに対して、Haskell のような代数的データ型では、値の集合を定義するのみで、操作を定義する場合、別に関数定義する。

     

    4. 型クラスの役割

    では、「型クラス」とは何か?

    Type class - Wikipedia によると、

    Type classes first appeared in the Haskell programming language, and were originally conceived as a way of implementing overloaded arithmetic and equality operators in a principled fashion.

     A Gentle Introduction to Haskell: Classes には、

    There is one final feature of Haskell's type system that sets it apart from other programming languages. The kind of polymorphism that we have talked about so far is commonly called parametric polymorphism. There is another kind called ad hoc polymorphism, better known as overloading.

    Here are some examples of ad hoc polymorphism:

    • The literals 1, 2, etc. are often used to represent both fixed and arbitrary precision integers.
    • Numeric operators such as + are often defined to work on many different kinds of numbers.
    • The equality operator (== in Haskell) usually works on numbers and many other (but not all) types.

    (太字は引用者による)

    型クラスは、Haskell の特徴の一つで、Haskell で初めて導入された。多相性には、パラメータ多相と、アドホック多相があり、後者はオーバーロードと呼ばれる。

    型クラス(Type class - Wikipedia) の説明に戻る。

    a type class is a type system construct that supports ad-hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types. Such a constraint typically involves a type class T and a type variable a, and means that a can only be instantiated to a type whose members support the overloaded operations associated with T.

    090513-002.png上記について、「Haskell の代数的データ型と型クラス、instance 宣言の関係」で使い方を確認した。しかし、そのとき、代数的データ型と、型クラスの関係が理解しにくく、知識として定着しなかった。

    オブジェクト指向におけるオーバーロード、オーバーライドには馴染みがある。しかし、パラメータ多相、アドホック多相、それに加えて、型クラスがどう絡んでいるのかイメージがしずらい。(+_+)

    「アドホック多相は、関数を適用する対象を制約するための手段。 Haskell では、それを型クラスによって実現している。」

    と頭に叩き込もうとした。しかし、直観的に理解できず、しっくり来なかった。 (@_@;)

    090514-006.pngしかし、次のように考えたら、スッキリした。

    1. 型は値をグループ化する。
    2. 型クラスは、型をグループ化する。
    3. その結果、型クラスの制約が付いた関数は、その型クラスのグループに属していない型には適用できない。
    4. インスタンス化とは当該の型クラスに所属する宣言。

     

    5. パラメータ多相と、アドホック多相

    Type polymorphism - Wikipedia によると、Christopher Strachey が、二つの異なる多相について述べていたとのこと。

    それによると、「アドホック多相」とは、

    If the range of actual types that can be used is finite and the combinations must be specified individually prior to use …

    それに対して、「パラメータ多相」とは、

    If all code is written without mention of any specific type and thus can be used transparently with any number of new types …

    つまり、アドホック多相は、関数を適用する型を制限するのに対して、パラメータ多相は、具体的な型について言及しないことにより、新しい型に対応できるようにするということ。

     

    6. 多相性とオブジェクト指向

    パラメータ多相と、アドホック多相は、オブジェクト指向において、どのように対応しているのだろうか?

    Polymorphism (computer science) - Wikipedia によると、

    In object-oriented programming, subtype polymorphism or inclusion polymorphism is a concept in type theory wherein a name may denote instances of many different classes as long as they are related by some common super class.[1] Inclusion polymorphism is generally supported through subtyping, i.e., objects of different types are entirely substitutable for objects of another type (their base type(s)) and thus can be handled via a common interface. Alternatively, inclusion polymorphism may be achieved through type coercion, also known as type casting.

    オブジェクト指向においては、サブタイプ多相と呼ばれる。オブジェクトが、共通のインターフェイスを実装している場合、他のオブジェクトに置き換えることができるというもの。

    また、Operator overloading - Wikipedia によると、

    (less commonly known as operator ad-hoc polymorphism) …

    operators like +, =, or == have different implementations depending on the types of their arguments.

    演算子オーバーロードは、アドホック多相に相当するとのこと。

    オーバーロードと言えば、以下のようにいくつか種類がある。

  • Function overloading, a software engineering process whereby multiple functions of different types are defined with the same name
  • Operator overloading, a software engineering process whereby operators such as + or - are treated as polymorphic functions having different behaviours depending on the types of arguments used
  • Method overloading a type of polymorphism where different functions with the same name are invoked based on the data types of the parameters passed

    (Overload - Wikipedia, the free encyclopedia より)

  •  

    7. 演算子の意味

    ところで、「演算子」というと、Java しか知らなかったとき、メソッドとの違いを明確にイメージしていた。

    `+’ のように、「メソッド名にできない記号が演算子」と言う意識。

    この Java の仕様は、以下で述べられている。

    Sun deliberately chooses not include operator overloading in the Java language.

    (Operator overloading - Wikipedia, the free encyclopedia より)

    Ruby は Java と違い、再定義可能な演算子 がある。

    |  ^  &  <=>  ==  ===  =~  >   >=  <   <=   <<  >>
    +  -  *  /    %   **   ~   +@  -@  []  []=  `

    Haskell は、 Haskell 98 字句構造 で述べられている。

    Python は、__XXXXX__() という形の 特殊メソッド を、クラスが実装することによって、同様のことが可能。

    そういえば、Haskell に触れるようになってから、関数と演算子の差異をあまり感じなくなった。なぜなら、関数の中置記法があるため。

    演算子 – Wikipedia とは、

    コンピュータプログラミングにおいては、主に記号を用いて演算を指示するものが演算子と呼ばれる。概ね数式などの記述を模倣しているが、一部の演算子に通常と異なる記号が用いられたり、副作用を持っていることがあるなど、数学の演算子とは異なる点もある。

    関数 f(x) の "f( )" も単項演算子であり、符牒となる文字列 "f" を関数子などと呼ぶ場合もある。関数子としては任意の文字列を使用することができ、代表的なものとして三角関数 "sin", "cos", "tan" などが挙げられる

    つまり、演算子も関数も、使える記号と記法が違うだけで、本質的な違いはない。

    考えてみれば、メソッドオーバーロードは、同一クラス内で、異なる引数に対する処理に、同じ名前を付けること。メソッドの引数を、関数プログラミングで言う適用する対象と見れば、メソッドオーバーロードは、メソッドが所属するクラスは同じでも、適用する対象が異なるという点で、演算子オーバーロードと似ている。

    「メソッドのシグニチャは、なぜ返り値を含まないんだ?」

    と、以前から疑問に思っていた。しかし、1 + 2 と 3 + 4 の結果、型が異なるような実装ができたらおかしいか。

     

    8. 継承とジェネリクス

    話を戻して、オブジェクト指向におけるアドホック多相とは、オーバーロードに相当する。

    先に挙げた Christopher Strachey  の言うところの

    「メソッドの引数の型がある範囲に限られている」

    ということによる。

    型が「限られている」という点から見ると、

    Ad-hoc polymorphism is generally supported through object inheritance, …

    (Type polymorphism - Wikipedia より)

    オブジェクト指向の継承も、アドホック多相に相当する。

    逆に、「限定されていない」と言うのは、090518-002.png

    In the object-oriented programming community, programming using parametric polymorphism is often called generic programming.

    ジェネリクスのこと。

     

    9. Ad hoc の意味

    ところで、「アドホック」というと

    アドホックな仮説 - Wikipedia

    という使われ方を連想する。言葉自体に、良いイメージがない。

    そもそもの意味は Yahoo!辞書 - ad hoc によると、

    ((限定))そのためだけに[の], 特別に[な]

    Ad hoc - Wikipedia には、

    Ad hoc is a Latin phrase which means "for this [purpose]". It generally signifies a solution designed for a specific problem or task, non-generalizable, and which cannot be adapted to other purposes.

     

    10. 型クラスの定義と、インスタンス化

    さて、最初の「犬・猫」型のコードに戻る。型クラスを使い、異なる型に、同じ関数名を適用できるようにしたい。

    そのためには、型をグループ化する、型クラスを定義する。

    Name.hs

    module Name where
        class Name a where
                getName :: a -> String

    次に Dog.hs

    module Dog where
        import Name
        data Dog = Dog {name :: String, age :: Int} deriving Show
        instance Name Dog where
               getName (Dog name age) = name

    同じようにして Cat/Mike.hs

    module Cat.Mike where
        import Name
        data Mike = Mike {name :: String, age :: Int}
        instance Name Mike where
                    getName (Mike name age) = name

    ついでに、メインモジュールにおいて、getName 関数を利用して

    「こんにちは!○○.」

    と出力する hello 関数も定義する。

    import Dog
    import Person
    import Name
    import Cat.Mike
    
    hello :: Name a => a -> String
    hello x = "Hello! " ++ getName x ++ "."
    
    main = do print $ getName (Mike "mike" 100)
              putStrLn $ hello (Mike "mike" 30)

     

    11. 余談: モジュールに分けない場合

    もし、モジュールに分けずにシンプルに書くとしたら、

    1. 犬と猫に共通の Pet 型を作り、
    2. そこで名前と年齢を持たせる。

    ついでに、犬と猫を同じ型にして、定義してみた。

    data Pet = Pet { name :: String, age :: Int }
    data MyPet = Dog Pet | Cat Pet
    
    getName :: MyPet -> String
    getName (Dog p) = name p
    getName (Cat p) = name p
    
    main = do print $ getName $ Dog (Pet "Pochi" 10)
              print $ getName $ Cat (Pet "Tama" 3)

     

    関連記事

    関連サイト

    2009年4月18日土曜日

    時刻を扱う - 特定の日付に属さない時間

    例えば、「いつも朝の 6:30 から 6:40 までラジオ体操をする」という事柄を表現したいとする。「いつも」とあるように、この表現は特定の日付と関連したものではない。過去のある期間においてそういう事実があったことを記録したいわけでもなく、未来の予定について述べているわけでもない。「日常」という言葉通り、典型的な「生活パターン」というような抽象的なレベルの事象をどのように表現して扱うかという問題。

     

    Access の日付/時刻型

    さて、Access でデータを管理しようと思うと、上記の「時刻」をどのデータ型で扱えばいいのだろうか?最初に思い付くが「日付/時刻型」。(cf.  Access で使用できるフィールドのデータ型 (MDB) - Access - Microsoft Office Online)

    「日常生活」と命名したテーブルを以下のように定義し、

    090417-001

    データを入力したとする。

    090417-002

     

    これに対して、次のように「年月日」を表示させるクエリを実行すると、

    SELECT 日常生活.id, 日常生活.内容, Format([開始時刻],"yyyy/mm/dd hh:nn") AS 式1, Format([終了時刻],"yyyy/mm/dd hh:nn") AS 式2
    FROM 日常生活;

    時刻の前に `1899/12/30’ が表示される。これでは表現したいデータを素直に表現しているとは言い難い。 (+_+)

    090417-003

    ちなみにこの日付となる理由は、「フィールドのデータ型の設定を修正または変更する - Access - Microsoft Office Online」によると、

    Access では、1899 年 12 月 30 日が日付 0 として使用されます。

     

    時間について

    プログラマのためのSQL 第2版 (P64) によると、

    時間に関する重要な問題の 1 つに、時間には 3 種あるというのがあります。固定された出来事「彼は、13:00 に到着した」、期間「その旅は 3 時間かかる」、時間間隔「その列車は 10:00 に出発して 13:00 に到着する」は、それぞれ依存関係を持っています。 SQL-92 は、 INTERVAL データ型を導入していますが、ほとんどの現実の実装 (…) では、明白に持っていません。

    (太文字は引用者による)

    SQL – Wikipedia を見ると、SQL-92 で INTERVAL が追加されているのがわかる。

    データ型の拡張 (可変長文字列、ビット、文字集合、日付・時刻・時間間隔 (DATE, TIME, TIMESTAMP, INTERVAL))

    どうやらこの「時間間隔」というのが考える手がかりになりそうだ。

    ちなみに Access と SQL のデータ型を比較した表を見ると、Access では INTERVAL 型を直接表現した型がないことがわかる。

     

    ところで、Access ではユーザ定義型を作成することができない。(型とその型に適用できる演算子の定義がまともにできる RDB ってどれくらいあるのだろう?) よって、上記の要求を満たすドメインの値を素直に保持することはできない。そのため、結果として機能し得る型で代用することになる。

     

    MySQL の Time 型

    MySQL :: MySQL 5.1 Reference Manual :: 10.3.2 The TIME Type によると、

    MySQL retrieves and displays TIME values in 'HH:MM:SS' format (or 'HHH:MM:SS' format for large hours values). TIME values may range from '-838:59:59' to '838:59:59'. The hours part may be so large because the TIME type can be used not only to represent a time of day (which must be less than 24 hours), but also elapsed time or a time interval between two events (which may be much greater than 24 hours, or even negative).

    MySQL 5.1 では「時間間隔」と「一日の時刻」を同じ Time 型で表わすようだ。というより、「一日の時刻」を「時間間隔」で代用しているということかな。

     

    Postgres の interval 型と time 型

    Postgres は、「時間間隔」 (Interval) と「その日の時刻」(time) が分かれている。

     

    Python の time オブジェクト

    ところで、以前に Python で指定した日数後の日付を得るのに timedelta オブジェクト を使ったことがある。timedelta 周りを見ると time オブジェクト があるのに気がついた。(@_@)

    time クラスは、

    理想化された時刻表現で、あらゆる特定の日における影響から独立しており、毎日厳密に 24*60*60 秒であると仮定します ("うるう秒: leap seconds" の概念はありません)。 属性: hourminutesecondmicrosecond、 および tzinfo

    (5.1.1 利用可能なデータ型 より)

    まさにこれ。ただし、

    time オブジェクト間の四則演算はサポートされていないので注意してください。

    (time オブジェクト より)

    「年月日」がなく「時・分・秒」だけので、上記の例を表現するには概念的にちょうどいい。

     

    Visual Basic の日付

    VB にも、似たような見かけの TimeSerial 関数 があったが、

        Debug.Print TimeSerial(6, 30, 0)
        Debug.Print Format(TimeSerial(6, 30, 0), "yyyy/mm/dd hh:nn")

    実行すると、

    6:30:00 
    1899/12/30 06:30

    あ~、内部では日付型かぁ…

    @IT:連載:プロフェッショナルVB.NETプログラミング 第5回 日付時刻の取得とフォーマット によると、

    日付と時刻の扱いは、Microsoft系BASICの歴史に限ってもすでに激変が起きている。初期のBASICでは、日付と時刻はそれぞれ文字列として扱われており、日付と時刻は別個の情報として扱われていた。(…)

    Timeの場合日付は1899年12月30日となっているが、これはVB 6の日付を扱う起点となる日付である。(…)

    VB.NETでは日付時刻の起点は0001/01/01 12:00:00である

    うーむ… (@_@;)

     

    Haskell の TimeOfDay 型

    では、Haskell ではどうかな?と思い調べてみると、Time of day に、

    data TimeOfDay

    Time of day as represented in hour, minute and second (with picoseconds), typically used to express local time of day.

    「時・分・秒」のみを値に持つ型がある。

    先ほどの Python の Time オブジェクトと同様に、TimeOfDay 型は Num クラスのインスタンスではないので四則演算はできない。ただし、DiffTime 型という「時間間隔」を表わす型を利用すると計算を行うことができる。

    最初に timeOfDayToTime 関数で TimeOfDay 型を DiffTime 型に変換。この関数は午前 0 時からの時間間隔を返してくれる。

    timeOfDayToTime :: TimeOfDay -> DiffTime

    090417-001

    DiffTime 型は Num クラスのインスタンスなので、この型の値を足したり引いたりできる。それを上記の関数とは逆の timeToTimeOfDay で元の型に戻す。例えば、

    import Data.Time
    main = do
      let s = TimeOfDay 6 30 0
      print s
      let ds = timeOfDayToTime s
      print ds
      print $ timeToTimeOfDay $ ds + (secondsToDiffTime (10*60))

    結果は、

    06:30:00
    23400s
    06:40:00

     

    対応する型がない場合の妥協

    さて、話を元に戻して Access で時刻を扱うにはどうしよう。

    一つは、年月日の情報は無視して、つまり ‘1899/12/30’ はないものとして時刻だけを「日付/時刻型」で扱う。とりあえず楽な方法。

    自前でどうにかしたいなら、「時・分・秒」をそれぞれ別のフィールドで数値として扱い、それを一塊のものとして自分で思い込み、「時・分・秒」間での計算が必要なら関数を定義。ちょっと面倒だし、それに見合ういいことがあるのかわからない。

    また別の方法として、NULL撲滅委員会 にあるように、

    日付の列は文字型で宣言しておくべきです。(…) ほとんどの DBMS が日付型を用意していますが、私は個人的に使うメリットを感じません。暦日計算の場合など、必要なときだけキャストしています。

    時刻を文字列として保持し、必要なときだけキャストする。ただし、年月日の情報は無視して日付型として計算を行う。この場合、最低でも文字列として時刻を保存するとき、時刻へとキャスト可能な形式であるか確認する必要となる。

    2008年10月17日金曜日

    Haskell でフィールドに型変数を含んだ型の print

    前回の「Haskell で代数的データ型の値を print で出力」では、型のフィールドに型変数が含まれていなかった。今回はフィールドに型変数が含まれる場合について試してみる。

     

    Iremono a 型

    例えば、何でも入る「入れ物」を想定し、型変数を一つフィールドに持つ `Iremono a 型’ を定義。

    data Iremono a = Iremono a

    これを print で出力できるようにしたい。

     

    instance Show Iremono

    ここで、次のように Iremono を Show クラスのインスタンスにすると、

    instance Show Iremono

    次のように怒られる。 (+_+)

        `Iremono' is not applied to enough type arguments
        Expected kind `*', but `Iremono' has kind `* -> *'
        In the instance declaration for `Show Iremono'

    これは kind と言って、型を分類するための概念らしい。 (cf. Kind – HaskellWiki) 詳しくはわからないので横に置いておく。 ^^; QQQ

     

    instance Show (Iremono a)

    ところで、Show クラスのインスタンスにしたい対象は Iremono 型ではなくて Iremono a 型。( Iremono は型ではなくて、型コンストラクタ) だから次のように、

    instance Show (Iremono a) where
        show (Iremono x) = "nakami ari"
    
    main = print $ Iremono 100

    上記は入れ物の中に中身がある場合に「中身あり」と表示させるようにしただけ。

     

    instance Show a => (Iremono a)

    しかし、普通 print と言ったら、その中身を表示させたいので、

    instance Show (Iremono a) where
        show (Iremono x) = show x

    これでいいのかなと思いきや、また怒られた。 (+_+)

        Could not deduce (Show a) from the context (Show (Iremono a))
          arising from a use of `show' at functest.hs:4:23-28
        Possible fix:
          add (Show a) to the context of the type signature for `show'
        In the expression: show x
        In the definition of `show': show (Iremono x) = show x
        In the definition for method `show'

    deduce とか難しいことが書かれている (@_@;) けれど、ゆっくりとエラーの内容を読むと、show x の式が問題なことがわかる。show x の x と言ったら、「入れ物」の `中身’ のこと。これはどんな型でも入れることができるので、show を適用できるかどうかはわからない。だから、次のように `中身’ も Show クラスのインスタンスでないといけないことを示す必要がある。

    instance Show a => Show (Iremono a) where
        show (Iremono x) = show x

     

    全体を示すと、

    data Iremono a = Iremono a
    
    instance Show a => Show (Iremono a) where
        show (Iremono x) = show x
    
    main = print $ Iremono 100

    結果は、

    100

     

    deriving

    前回教えていただいたように deriving を使うと、instance Show … を書かなくても、

    data Iremono a = Iremono a deriving Show
    
    main = print $ Iremono 100

    結果は、次のように表示される。

    Iremono 100

     

    参考

    2008年9月26日金曜日

    Python で変数の型 (クラス) を調べる – types モジュール


    1. type, isinstance 関数で、変数の型を調べる

    Python で、変数の中身が、どのクラスに所属するのか、または、関数なのか調べたい。

    2.1 組み込み関数 によると、 (装飾は、引用者による)

    type(object)
    object の型を返します。返される値は型オブジェクトです。
    isinstance(object, classinfo)
    引数 object が引数 classinfo のインスタンスであるか、 (直接または間接的な) サブクラスのインスタンスの場合に真を返します。
    例えば、「数値」の場合、次のようにして、数値に対して type 関数を適用する。
    print type(100)    #=> <type 'int'>
    type 関数の結果を用いて、isinstance 関数の引数に指定した。
    print isinstance(100, int)    #=> True

    追記 (2011.12.10) :  Python 2.6 では、型の検査として、type 関数は推奨されていない。

    type(object)(原文)

    object の型を返します。オブジェクトの型の検査には isinstance() 組み込み関数を使うことが推奨されます。

     

    関数に対して、type 関数は使えない

    次に、関数に対して、type 関数を適用してみる。

    def hoge():
        pass
    
    print type(hoge)    #=> <type 'function'>
    
    print isinstance(hoge, function) # ここでエラー 

    実行したら、以下のエラーが表示された。

    exceptions.NameError: name 'function' is not defined

    あれ? (+_+)

     

    2. types モジュールに、型の名前が定義されている

    先ほどの type 関数の説明の続きに、 次のようにある。

    標準モジュール types は、組み込み名を持っていない全ての組み込み型の名前を定義しています。

    (同上より、装飾は引用者による)

    3.6 types -- 組み込み型の名前 を参照すると、型の一覧が書かれていた。

    このモジュールは標準のPythonインタプリタで使われているオブジェクトの型について、名前を定義しています

    (同上より)

    これによると、「関数」は、

    FunctionType
    ユーザー定義の関数またはlambdaの型です。
    LambdaType
    FunctionTypeの別名です。

    よって、次のように書ける。

    import types
    print type(hoge) is types.FunctionType
    print isinstance(hoge, types.FunctionType)

    ちなみに、isinstance 関数において str , int などを型として利用できる理由は、 次の通り。

    Python 2.2以降では、int()str()のようなファクトリ関数は、型の名前となりましたので、typesを使用する必要はなくなりました。

    (同上より)

     

    参考サイト