LoginSignup
1
0

More than 1 year has passed since last update.

Haskellで整数の剰余環を実装する

Posted at

Qiita初投稿です。
Haskellの練習として、整数の剰余環 $\mathbb{Z}/m\mathbb{Z}$ の実装に挑戦してみます。
特に次の2つを目標にします。

  • 整数の剰余環をNumクラスのインスタンスとして実装する。
  • abで法が異なる場合、a + bなどはコンパイルが通らないようにする。

実装

整数の剰余環を実装するにあたって、以下の記事を参考に致しました。

型レベルの自然数についてはまだ十分に理解できていませんが、とりあえず整数の剰余環は実装できたのではないかと思います。

Main.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}

import Data.Proxy
import GHC.TypeLits

newtype IntMod (m :: Nat) = IntMod Integer

instance KnownNat m => Show (IntMod m) where
  show t@(IntMod x) = show x ++ " (mod " ++ show (natVal t) ++ ")"

instance KnownNat m => Num (IntMod m) where
  fromInteger x = IntMod (mod x (natVal (Proxy :: Proxy m)))
  (IntMod x) + (IntMod y) = fromInteger (x + y)
  (IntMod x) * (IntMod y) = fromInteger (x * y)
  negate (IntMod x) = fromInteger (-x)
  abs = id
  signum _ = IntMod 1

main = do
  let a = fromInteger 12 :: IntMod 101
  let b = fromInteger 34 :: IntMod 101
  print $ a + b
  print $ a - b
  print $ a * b
  print $ a ^ 100
結果
46 (mod 101)
79 (mod 101)
4 (mod 101)
1 (mod 101)

計算結果が正しいか確認します。

main = do
  let a = 12
  let b = 34
  print $ mod (a + b) 101
  print $ mod (a - b) 101
  print $ mod (a * b) 101
  print $ mod (a ^ 100) 101
結果
46
79
4
1

正しく計算できていそうですね。
ちなみに、4番目に計算しているa ^ 100ですが、フェルマーの小定理から計算するまでもなく1であるとわかります。

法が異なる場合も確認してみましょう。

main = do
  let a = fromInteger 12 :: IntMod 101
  let b = fromInteger 34 :: IntMod 103 -- 法を101から103に変更
  print $ a + b
  print $ a - b
  print $ a * b
  print $ a ^ 100
結果
Main.hs:24:15: error:
    ? Couldn't match type ‘103’ with ‘101’
      Expected type: IntMod 101
        Actual type: IntMod 103
    ? In the second argument of ‘(+)’, namely ‘b’
      In the second argument of ‘($)’, namely ‘a + b’
      In a stmt of a 'do' block: print $ a + b
   |
24 |   print $ a + b
   |               ^

ちゃんとコンパイルが通らずにエラーが出ました。

感想など

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}

言語拡張が3つありますが、今の所あまり理解できていません。
今回の場合では型レベルの自然数を扱うために用いているのだと思うのですが、それ以外の例も知りたいところです。

import Data.Proxy
import GHC.TypeLits

こちらもその他の例を知りたいですね。

abs = id
signum _ = IntMod 1

HaskellでNumクラスのインスタンス宣言をする際、ここがどうしても気になるところですね。
特に環をHaskellで実装しようとすると、(+)(*)は欲しいけどこの2つはいらないことが多い気がします。
とりあえず、上のように定義しておきました。

今回は型レベルの自然数を用いて整数の剰余環を実装しましたが、より一般の剰余環も同様に実装出来るのかが気になりました(例えば多項式環の剰余環など)。
また、型レベルのプログラミングには興味があるので、今後より詳しく勉強してみたいと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0