Преобразование x
в Rational
здесь будет недостаточно. Так как вы здесь пишите 1 % f xs
. Тип (%)
равен (%) :: Integral a => a -> a -> Ratio a
, и поскольку f xs
является Rational
, а Rational
не является экземпляром Integral
, нам необходимочтобы исправить вторую проблему.
Однако это не так сложно. Например, мы можем создать функцию, которая вычисляет обратное значение:
inverseR :: Integral a => Ratio a -> Ratio a
inverseR r = denominator r % numerator r
Поскольку Ratio a
является экземпляром Num
, а a
является экземпляром Integral
, мы можем использовать fromInteger :: Num a => Integer -> a
:
f :: [Integer] -> Rational
f [x] = fromInteger x
f (x:xs) = fromInteger x + inverseR (f xs)
Например:
Prelude Data.Ratio> f [1,4,2,5]
60 % 49
С 1 + 1 / (4 + 1 / (2 + 1/5))) = 1 + 1 / (4 + 1 / (11/5)) = 1 + 1 / (4 + 5/11) = 1 + 1 / (49/11) = 1 + 11/49 = 60/49.
Мы можем улучшить это следующим образом:
- , используя
fromIntegral :: (Integral a, Num b) => a -> b
для преобразования любого интеграла в Ratio
;и - с помощью
(/) :: Fractional a => a -> a -> a
.
Таким образом, мы можем обобщить это для функции:
f :: (Integral a, Fractional b) => [a] -> b
f [x] = fromIntegral x
f (x:xs) = fromIntegral x + 1 / f xs
Что дает одно и то же значение:
Prelude Data.Ratio> f [1,4,2,5] :: Rational
60 % 49
Мы можем использовать шаблон foldr
и избежать явной рекурсии:
f :: (Integral a, Fractional b) => [a] -> b
f = foldr1 (\x -> (x +) . (1 /)) . map fromIntegral