Comment detail
法演算 (Nested Flatten)これはおもしろい。適切なinstance定義が与えてあれば、型推論によって1などのリテラルさえも後つけのModulo型と解釈させることができちゃうわけですね。duck typingみたいだなあ。
Haskell での 0 とか 1 などの整数表記リテラルの型を調べると、 % ghci GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help Loading package base ... linking ... done. Prelude> :type 0 0 :: (Num t) => t Prelude> :type 1 1 :: (Num t) => t のように Numクラスのインスタンスである型になります。 ということは、Numクラスのインスタンスであると宣言された型が 出現するべきだと型推論されたところで表れた整数表記リテラルは 当該の型であること認識できるというわけです。この場合 Modulo a b 型は、aがNatクラスのインスタンス、bがIntegralクラス のインスタンスである文脈でNumクラスのインスタンスであると宣言 されていますので、Modulo Ten Int やModulo Seven Int が来るべき 場所で整数表記リテラルが出現すれば、それぞれの型として解釈されます。
以前に有限体GF(p)を扱うのに同様の方法を使ってみたことがあるので、参考までに転載します。
nobsunのコードとほぼ同じですが、法が素数の場合には除算もできるようになっています。
see: 有限体GF(p) - ヒビルテ (2005-07-19)
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)
-}
-----------------------------------------------------------------------------
|





nobsun
#4948()
[
Haskell
]
Rating3/3=1.00
Rating3/3=1.00-0+
2 replies [ reply ]