Comment detail

法演算 (Nested Flatten)

This comment is reply for 4948 nobsun: 依存型風に書いてみました.法は型で与えま...(法演算). Go to thread root.

以前に有限体GF(p)を扱うのに同様の方法を使ってみたことがあるので、参考までに転載します。 nobsunのコードとほぼ同じですが、法が素数の場合には除算もできるようになっています。
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}
module GF
    ( Z
    , S
    , Nat
    , Prime
    , GF
    , GF2
    , GF3
    , GF5
    --, gf
    ) where

import Data.Ratio (denominator, numerator)
--import Language.Haskell.TH

-----------------------------------------------------------------------------

data Z
data S n

newtype NatInt n = NatInt Int

class Nat n where
    natInt :: NatInt n

instance Nat Z where
    natInt = NatInt 0

instance Nat n => Nat (S n) where
    natInt = case (natInt :: NatInt n) of
             NatInt n -> NatInt (n+1)

-----------------------------------------------------------------------------

class Nat n => Prime n
instance (Nat n, PrimeTest (S (S n)) (S (S n))) => Prime (S (S n))

-- p は {x | 1<x<a} では割り切れない
-- 実装は手抜き
class PrimeTest p a
instance PrimeTest p (S (S Z))
instance (PrimeTest p (S (S a)), NotDivide (S (S a)) p)
    => PrimeTest p (S (S (S a)))

-- aはbを割り切らない
class NotDivide a b
instance NotDivide' a a b => NotDivide a b
class NotDivide' a x y
instance NotDivide' (S a) (S y) Z 
instance NotDivide' (S a) a y => NotDivide' (S a) Z (S y)
instance NotDivide' (S a) x y => NotDivide' (S a) (S x) (S y)

-----------------------------------------------------------------------------

newtype GF p = GF Int deriving Eq

fromInt :: forall p. Nat p => Int -> GF p
fromInt a =
    case (natInt :: NatInt p) of
    NatInt p -> GF (a `mod` p)

toInt :: GF p -> Int
toInt (GF x) = x

instance Nat p => Show (GF p) where
    showsPrec n (GF x) = showsPrec n x

instance Nat p => Read (GF p) where
    readsPrec n s = [(fromInt a, s') | (a,s') <- readsPrec n s]

instance Nat p => Num (GF p) where
    GF a + GF b   = fromInt $ a+b
    GF a * GF b   = fromInt $ a*b
    GF a - GF b   = fromInt $ a-b
    negate (GF a) = fromInt $ negate a
    abs a         = a
    signum _      = 1
    fromInteger   = fromInt . fromIntegral

instance Nat p => Ord (GF p) where
    GF a `compare` GF b = a `compare` b
    GF a `max` GF b = GF (a `max` b)
    GF a `min` GF b = GF (a `min` b)

instance Nat p => Bounded (GF p) where
    minBound = 0
    maxBound =
        case (natInt :: NatInt p) of
        NatInt p -> GF (p - 1)

instance Nat p => Real (GF p) where
    toRational (GF x) = toRational x

instance Prime p => Fractional (GF p) where
    fromRational r =
        fromInteger (numerator r) / fromInteger (denominator r)
    _ / 0 = error "divide by zero"
    (GF x) / (GF y) =
        case (natInt :: NatInt p) of
        NatInt p ->
            case exGCD y p of
            (a,_,_) -> fromInt (a*x)

-- 拡張ユークリッド互除法
exGCD :: Int -> Int -> (Int,Int,Int)
exGCD x y = loop x y 1 0 0 1
    where loop x y a0 a1 b0 b1
              | y == 0 = (a0,b0,x)
              | otherwise = loop y r a1 (a0 - q*a1) b1 (b0 - q*b1)
                  where (q,r) = x `divMod` y

instance Nat p => Enum (GF p) where
    toEnum x
        | toInt (minBound :: GF p) <= x
          && x <= toInt (maxBound :: GF p) = fromInt x
        | otherwise = error "GF.toEnum: bad argument"
    fromEnum (GF x) = x

-----------------------------------------------------------------------------

type GF2 = GF (S (S Z))
type GF3 = GF (S (S (S Z)))
type GF5 = GF (S (S (S (S (S Z)))))

-----------------------------------------------------------------------------

{-
gf :: Int -> Type
gf x = AppT (ConT (mkName "GF.GF")) (f x)
    where f 0     = ConT (mkName "GF.Z")
          f (x+1) = AppT (ConT (mkName "GF.S")) (f x)
-}

-----------------------------------------------------------------------------

Index

Feed

Other

Link

Pathtraq

loading...