Haskellで新しい型を定義する

そもそも、今日はderivingについて書こうと思っていたのですが、その前に型を作る段階で一つ記事が書けるレベルの内容だったので、まずはちょっとした型を定義してみる事にします。

module Main where

--型 Bar を作成
newtype Bar = Bar Int deriving (Eq,Read,Show)
--Bar と Int 間の変換
fromBar :: Bar -> Int
fromBar (Bar a) = a
toBar :: Int -> Bar
toBar a = Bar a
--二項演算の定義を簡易化
calcBar :: (Int -> Int -> Int) -> Bar -> Bar -> Bar
calcBar f a b = toBar $ fromBar a `f` fromBar b

--Numクラスのインスタンスにする
instance Num Bar where
  x + y = calcBar (+) x y
  x - y = calcBar (-) x y
  x * y = calcBar (*) x y
  abs a = toBar $ abs (fromBar a)
  signum a = toBar $ signum (fromBar a)
  fromInteger a = toBar $ fromInteger a

--実験用
incBar :: Bar -> Bar
incBar x = x + 1

どうでも良い話ですが、あちこちでよく見かけるHaskellのサンプルは、無駄にこ難しい事をやろうとしているなぁと思うことが多々あります。
確かに、上のBar型はInt型の再実装みたいな状態ですけど、新しい型の実装方法について試してみるなら、このくらいシンプルな例でも十分だと思うのですが・・・。

閑話休題

とにかく、上で定義したBar型ですが、普通にInt型と同じように使えます。

*Main> (5::Bar) + 10
Bar 15
*Main> (8::Bar) - 3
Bar 5
*Main> (5::Bar) * 4
Bar 20
*Main> incBar 10
Bar 11

単純にInt型を別名で定義したいのであれば、typeを使えば良いんですけどね。

module Main where
type Baz = Int;
*Main> (10::Baz)+5
15
*Main> :t (10::Baz)+5
(10::Baz)+5 :: Baz

ちなみに、除算は Fractional という、また別の型クラスになるみたいです。
Int型にも定義されていないようなので、Bar型で除算できるようにしようと思ったら、もうひと工夫必要でしょう。

*Main> (10::Bar)/2

<interactive>:1:0:
    No instance for (Fractional Bar)
      arising from a use of `/' at <interactive>:1:0-10
    Possible fix: add an instance declaration for (Fractional Bar)
    In the expression: (10 :: Bar) / 2
    In the definition of `it': it = (10 :: Bar) / 2
*Main> :t (/)
(/) :: (Fractional a) => a -> a -> a