2013-02-20 46 views
2

下面是在Data.Fixed之後建模的模塊化算術Num實例的實現。訪問幻像類型的返回值

我想寫一個替代實施fromRational這看起來是這樣的:

fromRational r = case invertMod (denominator r) theModulus of 
        Just inv -> normalize $ (numerator r) * inv 
        Nothing -> error "..." 

,但我想不出什麼我會用theModulus。與其他類型函數不同,我沒有Modular a類型的值,我可以在其中調用modulus

{-# LANGUAGE NoMonomorphismRestriction #-} 

import Math.NumberTheory.Moduli (invertMod) 
import Data.Ratio (numerator, denominator) 

class HasModulus a where 
    modulus :: p a -> Integer 

withType :: (p a -> f a) -> f a 
withType foo = foo undefined 

withModulus :: (HasModulus a) => (Integer -> f a) -> f a 
withModulus foo = withType (foo . modulus) 

newtype Modular a = M Integer 

normalize :: HasModulus a => Integer -> Modular a 
normalize x = withModulus $ \m -> M (x `mod` m) 

instance (HasModulus a) => Num (Modular a) where 
    (M a) + (M b) = normalize (a+b) 
    (M a) - (M b) = normalize (a-b) 
    (M a) * (M b) = normalize (a*b) 
    negate (M a) = normalize (-a) 
    abs   = id 
    signum _  = fromInteger 1 
    fromInteger = normalize 

instance (HasModulus a) => Fractional (Modular a) where 
    recip [email protected](M a) = case invertMod a (modulus ma) of 
        Just inv -> normalize $ inv 
        Nothing -> error "divide by zero error" 
    ma/mb  = ma * (recip mb) 
    fromRational r = (fromInteger $ numerator r)/(fromInteger $ denominator r) 

instance (HasModulus a) => Show (Modular a) where 
    show [email protected](M x) = (show x) ++ " mod " ++ (show $ modulus mx) 

data M5 = M5 
data M7 = M7 

instance HasModulus M5 where modulus _ = 5 
instance HasModulus M7 where modulus _ = 7 

bar = 1/3 

main = do print $ (bar :: Modular M5) 
      print $ (bar :: Modular M7) 

回答

1

一個方式來寫fromRational更接近你最初的Ansatz是

fromRational r = let x = case invertMod (denominator r) (modulus x) of 
          Just inv -> normalize $ (numerator r) * inv 
          Nothing -> error "..." 
       in x 

由於結果是Modular a,我們可以從中獲得模量(不檢查它)。所以我們只需要命名它,以便我們可以在需要的地方引用它。

+0

是的 - 這是我一直在尋找的東西。謝謝! – ErikR 2013-02-20 16:31:05

0

我想通了......關鍵是使用withModulus功能:

mdivide :: HasModulus a => Integer -> Integer -> Modular a 
mdivide x y = withModulus $ M . mdiv' x y 
       where mdiv' x y m = 
         case invertMod y m of 
          Just inv -> (x * inv) `mod` m 
          Nothing -> error "..." 

然後......

fromRational r = mdivide (numerator r) (denominator r)