在Haskell中实现Wiener算法 - 使用“wiener”产生的(RealFrac a0)实例

时间:2014-01-04 18:32:07

标签: haskell cryptography

我正在尝试在Haskell中实现密码学:理论与实践,第三版一书中的 Wiener算法。这是我到目前为止所写的内容:

import Data.List

wiener e n = factors
    where euclid = euclidean e n
          cs = 1 : head euclid : rest cs euclid
          ds = 0 : 1 : rest ds euclid
          ns = filter isInt $ drop 2 $ zipWith (\x y -> (x * e - 1) / y) ds cs
          qs = map (\x -> quad 1 (x - n - 1) n) ns
          factors = find (\(p, q) -> isInt p && 0 < p && p < n 
                                  && isInt q && 0 < q && q < n) qs
          rest xs ys = zipWith (+) xs (zipWith (*) (tail ys) (tail xs))

euclidean _ 0 = []
euclidean a b = a `div` b : euclidean b (a `mod` b)

quad a b c
    | d > 0     = ((-b + sqrt d) / (2 * a), (-b - sqrt d) / (2 * a))   
    | otherwise = (0.0, 0.0) 
    where d = b * b - 4 * a * c

isInt x = x == fromInteger (round x)

尝试wiener 238123333 293719721给了我:

No instance for (RealFrac a0) arising from a use of `wiener'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)

No instance for (Num a0) arising from the literal `238123333'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s

我该怎么办?是否有任何通用数字类型可以在任何地方使用?

1 个答案:

答案 0 :(得分:2)

我追踪了错误。 euclidean的返回类型为Integral a => [a],而quad返回RealFrac的实例。由于您使用值ne作为两个函数的参数,因此ne必须是两个类型的实例。

wiener :: (Floating b, Integral a, RealFrac b) => a -> a -> Maybe (b,b)
wiener e' n' = factors
    where euclid = map fromIntegral $ euclidean e' n'  -- convert result from `Integral` to `Num`
          e = fromIntegral e'                          -- convert Integral to Num
          n = fromIntegral n'
          cs = 1 : head euclid : rest cs euclid
          ds = 0 : 1 : rest ds euclid
          ns = filter isInt $ drop 2 $ zipWith (\x y -> (x * e - 1) / y) ds cs
          qs = map (\x -> quad 1 (x - n - 1) n) ns
          factors = find (\(p, q) -> isInt p && 0 < p && p < n 
                                  && isInt q && 0 < q && q < n) qs
          rest xs ys = zipWith (+) xs (zipWith (*) (tail ys) (tail xs))