質問:引数の型に応じて処理を分けたい

93 views
Skip to first unread message

大竹将吾

unread,
Oct 10, 2014, 6:24:23 AM10/10/14
to haske...@googlegroups.com
はじめまして。
最近Haskellの勉強を始めたものです。

以下のパッケージを使ってruby版のto_msgpackのような関数を作れたらなと思っています。
http://hackage.haskell.org/package/messagepack


toMessagePack :: [a] -> Int
toMessagePack (x: xs :: Int) = 1
toMessagePack (x: xs :: String) = 2

このような感じでaの型によって処理を分けたいのですがどのように書けば実現できるのでしょうか。
御教示頂けたら幸いです。
よろしくお願い致します。

Katsutoshi Itoh

unread,
Oct 10, 2014, 9:23:50 PM10/10/14
to haske...@googlegroups.com
アドホック多相をやりたいってことでいいのかな。
基本的にはMessagePackable(?)のようなクラスを用意して、to_msgpackなメソッドを用意しておいて、あとはIntやらStringやらをMessagePackableのインスタンスにしていくことになるかと思います。

2014年10月10日金曜日、大竹将吾<shogo...@gmail.com>さんは書きました:
--
このメールは Google グループのグループ「haskell-jp」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには haskell-jp+...@googlegroups.com にメールを送信してください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。


--
----
いとう かつとし
cuts...@gmail.com

Daniel P. Wright

unread,
Oct 11, 2014, 12:19:04 AM10/11/14
to haske...@googlegroups.com
イトウさんが言うとおり、型クラスを使わないとできないのです。

なぜかというと、Haskellのパターン照合は「型」ではなく「値」を照合するものです。
例えば、

data Bool = True | False

という型があれば、

f :: Bool -> Int
f True = 1
f False = 2

というパターン照合はできますが、

f Bool = 3

というのは、できません。

大竹さんが書いた型宣言、

> > toMessagePack :: [a] -> Int

では、「a」という引数の型は何も分からないので、
その型の値(BoolであればTrueかFalse、Intであれば1や2など)を照合できないのです。

このときはパターン照合ではなく、型クラス(アドホック多相)を使います。
こういう感じの型クラスがあれば、

class MessagePackable a where
toObject :: a -> Object
fromObject :: Object -> a

大竹さんの関数はこんな感じで宣言できます。

toMessagePack :: MessagePackable a => [a] -> Int

この場合は、「a」の値は一つ分かることが増えた。
それは、「toObject、fromObjectという関数が呼べる」ということです。
Objectの定義を見ると、

data Object = ObjectInt Int
| ObjectNil
| ObjectBool Bool
...

値はObjectIntだったらIntが入っている、ObjectBoolだったらBoolが入っている、
という形で定義されています。

これが持っていたら、値でパターン照合ができます。

toMessagePack (ObjectInt _ :xs) = 1
toMessagePack (ObjectString _ :xs) = 2

この場合は型(Int, Bool)ではなく値(ObjectInt, ObjectString)を照合しているので大丈夫です。

結構長い文章になってしまってすみません。
私は初めてHaskellを勉強したとき、この「型」と「値」の違いはなかなか分からなかったので、
少しでもお役に立ってたらいいなと思ってまとめてみました。

因みに下記のパッケージご存知ですか?

http://hackage.haskell.org/package/msgpack

こちらの方がOBJECTという型クラスが定義されてあるので、
ただ「IntをMessagePackにしたい」ということだったら
このパッケージの方が使いやすいかもしれません。

逆に「勉強のため、自分でしたい」と思っても、
Hackageで"source"のリンクをクリックしたらソースコードが見れるので、
参考になると思います。


Katsutoshi Itoh (Sat, Oct 11, 2014 at 10:23:47AM +0900) >>
> アドホック多相をやりたいってことでいいのかな。
> 基本的にはMessagePackable(?)のようなクラスを用意して、to_msgpackなメソッドを用意しておいて、あとはIntやらStringやらをMessagePackableのインスタンスにしていくことになるかと思います。
>
> 2014年10月10日金曜日、大竹将吾<shogo...@gmail.com>さんは書きました:
>
> > はじめまして。
> >
> > 最近Haskellの勉強を始めたものです。
> >
> >
> > 以下のパッケージを使ってruby版のto_msgpackのような関数を作れたらなと思っています。
> >
> > http://hackage.haskell.org/package/messagepack
> >
> >
> >
> > toMessagePack :: [a] -> Int
> > toMessagePack (x: xs :: Int) = 1
> > toMessagePack (x: xs :: String) = 2
> >
> >
> > このような感じでaの型によって処理を分けたいのですがどのように書けば実現できるのでしょうか。
> > 御教示頂けたら幸いです。
> >
> > よろしくお願い致します。
> >
> > --
> > このメールは Google グループのグループ「haskell-jp」に登録しているユーザーに送られています。
> > このグループから退会し、グループからのメールの配信を停止するには haskell-jp+...@googlegroups.com
> > <javascript:_e(%7B%7D,'cvml','haskell-jp%2Bunsu...@googlegroups.com');>
> > にメールを送信してください。
> > その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。
> >
>
>
> --
> ----
> いとう かつとし
> cuts...@gmail.com
>
> --
> このメールは Google グループのグループ「haskell-jp」の登録者に送られています。

大竹将吾

unread,
Oct 11, 2014, 1:24:16 AM10/11/14
to haske...@googlegroups.com
早速のお返事有り難うございます。

アドバイス通りできているかわかりませんがコードを書いてみました。

module Data.MessagePack.Packable (Packable(..)) where

class Packable a where
  toMessagePack :: a -> Int

instance Packable Bool where
  toMessagePack _ = 0

instance Packable Int where
  toMessagePack _ = 1

instance Packable Char where
  toMessagePack _ = 2

instance Packable [a] where
  toMessagePack [] = 3
  toMessagePack (x: xs) = 3 + toMessagePack xs

こんな感じであってますでしょうか?
よろしくお願い致します。

2014年10月11日土曜日 10時23分50秒 UTC+9 cutsea110:
アドホック多相をやりたいってことでいいのかな。
基本的にはMessagePackable(?)のようなクラスを用意して、to_msgpackなメソッドを用意しておいて、あとはIntやらStringやらをMessagePackableのインスタンスにしていくことになるかと思います。

2014年10月10日金曜日、大竹将吾<shogo.ot...@gmail.com>さんは書きました:
はじめまして。
最近Haskellの勉強を始めたものです。

以下のパッケージを使ってruby版のto_msgpackのような関数を作れたらなと思っています。
http://hackage.haskell.org/package/messagepack


toMessagePack :: [a] -> Int
toMessagePack (x: xs :: Int) = 1
toMessagePack (x: xs :: String) = 2

このような感じでaの型によって処理を分けたいのですがどのように書けば実現できるのでしょうか。
御教示頂けたら幸いです。
よろしくお願い致します。

--
このメールは Google グループのグループ「haskell-jp」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには haskell-jp+unsubscribe@googlegroups.com にメールを送信してください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

大竹将吾

unread,
Oct 11, 2014, 1:30:58 AM10/11/14
to haske...@googlegroups.com
ものすごく丁寧に教えて頂けてとても嬉しいです!
それを参考にfromMessagePackも作ってみようと思います!

http://hackage.haskell.org/package/msgpack
このパッケージですが、あまりメンテナンスされていないようなのと、勉強のために自分で書いてみたかったという気持ちがあります。

まだまだわからないことだらけなので、また質問させていただくかと思いますが、その時はよろしくお願い致します!

2014年10月11日土曜日 13時19分04秒 UTC+9 Daniel Wright:
> 2014年10月10日金曜日、大竹将吾<shogo.ot...@gmail.com>さんは書きました:
>
> > はじめまして。
> >
> > 最近Haskellの勉強を始めたものです。
> >
> >
> > 以下のパッケージを使ってruby版のto_msgpackのような関数を作れたらなと思っています。
> >
> > http://hackage.haskell.org/package/messagepack
> >
> >
> >
> > toMessagePack :: [a] -> Int
> > toMessagePack (x: xs :: Int) = 1
> > toMessagePack (x: xs :: String) = 2
> >
> >
> > このような感じでaの型によって処理を分けたいのですがどのように書けば実現できるのでしょうか。
> > 御教示頂けたら幸いです。
> >
> > よろしくお願い致します。
> >
> >  --
> > このメールは Google グループのグループ「haskell-jp」に登録しているユーザーに送られています。
> > このグループから退会し、グループからのメールの配信を停止するには haskell-jp+...@googlegroups.com
> > <javascript:_e(%7B%7D,'cvml','haskell-jp%2Bunsubscribe@googlegroups.com');>
Reply all
Reply to author
Forward
0 new messages