我正在尝试在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
我该怎么办?是否有任何通用数字类型可以在任何地方使用?
答案 0 :(得分:2)
我追踪了错误。 euclidean
的返回类型为Integral a => [a]
,而quad
返回RealFrac
的实例。由于您使用值n
和e
作为两个函数的参数,因此n
和e
必须是两个类型的实例。
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))