Haskell

2011年4月19日 (火)

Haskell Applicative Monoid

Img_0020_2

Applicativeな型の利点

Applicativeな型の利点として、通常の関数と、値を組み合わせられることがあるらしい。
>(\x y -> x + y) <$> (Just 3) <*> (Just 6)
Just 9

1つ目のラムダ式はただの関数。そこに2つのファンクター値を与えて演算している。

これは通常のFunctor type classのインスタンスではできない。(たぶん)

Monoid

モノイドは、ひとつの二項演算子と単位元を持つ代数的構造、らしい。(Wikipediaより)

二項演算子は、引数が2つ必要な関数(+,÷など)で、
単位元とは、集合の中の任意の要素に対して二項演算しても、もとの値を維持する要素のこと。

あと、結合法則(順序を入れ替えない限り、どこから計算しても良い)を満たす必要がある。

例えば、
 集合:整数
 二項演算子:「+」
 単位元:0

はモノイドである。(たぶん)
証明)
 X + 0 = X
 0 + X = X
 (X + Y) + Z = X + (Y + Z)

Monoid type classの定義



class Monoid m where
mempty :: m
mappend :: m -> m -> m
mconcat :: [m] -> m
mconcat = foldr mappend mempty

memptyが単位元で、mappendが二項演算子かな。

ただ、この定義だけでは、memptyが単位元であることや、
mappendで結合法則が満たされることは保証されない。

これは実装者に任されている。
これに違反したモノイドインスタンスを実装することは可能だが、
数学的な意味のモノイドとして役に立たない。

では、モノイドであることが、どう役に立つのか。

抽象

抽象的な、というのは、日本語では、あいまいな、となってしまうが。

一般的なアイデアや原則、ということで、モノイドの性質を考えれば、
モノイドな具体的な型の値の操作への武器になるのである。

それが何なのかは、まだ知らないがw


| | コメント (0) | トラックバック (0)

2011年4月17日 (日)

Haskell Functor type class 2

Functor のリベンジ

Functor type classの定義

class Functor f where fmap :: (a -> b) -> f a -> f b

fは、type constructorであり、具体的な型 a,bを受け取って、具体的な型になる。

(Maybeは具体的な型ではないが、Maybe Int は、具体的な型、ということです。)

f a の部分について、以下のようなパターンが想定できる。
・Maybe Int
・[Char]
・IO String
など

これは、なんらかの値をある文脈においた物、と理解できる。

たとえば、
Maybe Intの場合、Intの値をMaybeという文脈で理解する、ということ。

言い換えれば、数値が入っているか、何も無いか。

fmapは、このような文脈から、値を抜き出して(f a のaを取り出し)、演算し(a -> b)、文脈に戻す(f b)。

f aが、f bになるだけなので、文脈は変化しない。(Maybe Int -> [Char]にはならない)

Applicativeについて

Applicative type classの定義

class (Functor f) => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

<*>は、fmapに似ている。

fmapは、関数とFunctor値を引数にとって、Functor値を返す。
<*>は、Functor値(中身は関数)とFunctor値(中身は値)をとって、Functor値(中身は値)を返す。

Functor値とは、f(a->b)や、f aや、f bのことで、ある文脈に置かれた値(関数含む)のこと。

Functor値(中身は関数)というのは、例えば、Just(3+)のことで、これは、(3+)という関数をJustで包んでいることによって、
Maybe(a -> b)型の値になっている。

だからなんなのか。

Maybeに関して考えるなら、Maybe (a -> b)は、Nothingに成り得る。
関数をMaybeという文脈で考えるため、「引数をひとつもつ関数であるか、何も無いか」となる。

このため、<*>の左辺値は、Nothingでもよい。(Nothingが来たときの想定を含む実装をする)

これは、通常のFunctorでは表現できない。

>let a = fmap (+) (Just 3)
>a <*> (Just 6)
Just 9
>Nothing <*> (Just 6)
Nothing

Applicativeのインスタンスは、Maybeだけでなく、リストなどもある。

リストの中身に関数を持てる場合、どうなるか、と考えていく。

| | コメント (0) | トラックバック (0)

2011年4月12日 (火)

Haskell Functor type class

Functorとは、Type Classである。
Type Classとは、あるふるまいを定義するインタフェースである。
ある型があるType Classのインスタンスであるとき、その型はType Classの定義するふるまいを実装する。

Eq Type Class の 値が、イコール判定が可能なように、
Functor Type Class の 値は、マップ可能。

class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool

class Functor f where
fmap :: (a -> b) -> f a -> f b



Eq a の aは、具体的な型(Int, Char など)
Functor f の fは、type constructor である。
type constructorとは、具体的な型を受け取って型を作るもののこと。

例えば、Maybe Int のMaybeは、Intを受け取って、
具体的な型になるため、type constructorである。

Maybeは、パラメータを1つもつtype constructorであるため、
Functorのインスタンスと成り得る。(実際なっている。:i Maybe)

Functorのインスタンスであるので、次の記述が可能
>fmap (*2) (Just 3)
Just 6

>fmap (*2) Nothing
Nothing

これの何がうれしいのかはよくわからない。

Learn You a Haskell for Great Good!より

Types that can act like a box can be functors.
箱のように扱うことができる型は、ファンクターになり得る。

箱のように、とは、何か入ってるかもしれないし、空かもしれないもの。

Myabe aはまさにそのような型になる。


data Maybe a = Nothing | Just a

では、
data XXX a
とは、どういう意味か。これは、kindをとると、
>:k XXX
XXX :: * -> *
になるもので、XXXはFunctorのインスタンスに成り得る。

定義をもう一度見る。



class Functor f where
fmap :: (a -> b) -> f a -> f b

f aがあるときに、f bが欲しい。その場合、(a -> b)を用意して、
fmapを使えば良い。

fmap :: (a -> b) -> XXX a -> XXX b

具体的には、
fmap :: (Int -> Int) -> Maybe Int -> Maybe Int

やっぱり何がいいのかよくわからない。

逆から考えて、例えば、Just 3という値を2倍するには、fmap以外でどうできるか。

(Just 3) * 2、というのは許されない。

multi :: (a -> a ) -> Maybe a -> Maybe a
multi f (Just x) = Just (f x)
multi f Nothing = Nothing


>multi (*2) (Just 3)
Just 6

このような関数をわざわざ作らなくて良い、ということなのかな。

たぶんXXX aという型は、何か抽象的な意味があって、それに対する一般的な演算、ということなんだろうけど、イメージできない。

例えば、どういう型かは知らないが値が入っている箱があり、
その値を演算し、別の箱に入れ替える、というような。

箱の中身が1つの値であれば、Maybeであり、複数であれば、リストである、というような。

Haskell Functorで検索すると、数学的な解説が(群とか)出てくるんだけど、
あんなもの俺が理解できるわけがない。

(追記)ぜんぜんわかってないみたいなんで、後にまたエントリを作ります。

| | コメント (0) | トラックバック (0)

2011年4月 5日 (火)

Haskell 型と値 2

下記のように記述した場合、


data YYY a = ZZZ | XXX a

「ZZZ」または、「XXX a」は、型「YYY a」の値になる。

*Main> let x = XXX 100
*Main> :t x
x :: YYY Integer
*Main> :t ZZZ
ZZZ :: YYY a

「100」ではなく、「XXX 100」が、「値」なのが受け入れがたい。。

この形は、Maybe a の

data Maybe a = Nothing | Just a

から意味を抜いたものです。
「Just 100」という「値」を記述することで、「Maybe a」型の値が生まれるんでしょう。

(訂正)
上記、まちがってました。

*Main> :t Just
Just :: a -> Maybe a

Just は、関数で、aを受け取って、Maybe aを返します。
「Just 100」が値というのは、ある意味あってますが、関数Justに値100を与えた返却値として、
値になる、ということですね。

| | コメント (0) | トラックバック (0)

2011年4月 4日 (月)

Haskell 型と値

Haskellを勉強中です。

「Learn You a Haskell for Great Good!」という本の一部を翻訳します。


タイプのコンストラクタと値のコンストラクタを区別することが重要です。
データタイプを宣言したとき、「=」より左側は、タイプのコンストラクタです。
右側は、値のコンストラクタです。

次のような記述で考えると、


data Test a = Test a a [Char]

mySum :: (Num a ) => Test a -> a
mySum (Test x y _) = x + y

まず、Test a というタイプコンストラクタを宣言しています。
このaには、Intなどのタイプがきます。

つぎに、Test a a [Char]が、データのコンストラクタで、aがIntの場合、
Test Int Int [Char]と等価です。

関数mySumの定義をみると、ここは、宣言したデータ型 Test aを引数にとり、aを返す、となります。
具体例では、Test Int -> Int です。

関数の実装は、Test a型の値を受け取り、演算しています。

それぞれ、型を記述しているのか、値を記述しているのか、考える必要があるのです。

(実施結果)


*Main> mySum (Test 1.0 2.0 "abc")
3.0

| | コメント (0) | トラックバック (0)

その他のカテゴリー

Haskell | iphone アプリ | iphone開発 | javaScript | Kindle | 書籍