试图在haskell中将列表相乘
自从老师强迫我们学习哈斯克尔以来,我一直在学习。 作为练习,我们将尝试编写一个近似sin(x)函数的解决方案,使用Maclaurin级数直到第30项 我想到了用列表来表示1和-1的交替序列,将x提升为奇数,以及奇数的阶乘。然后,我将前两个列表相乘,最后一个列表相除。到目前为止,我只写了以下内容:试图在haskell中将列表相乘,haskell,Haskell,自从老师强迫我们学习哈斯克尔以来,我一直在学习。 作为练习,我们将尝试编写一个近似sin(x)函数的解决方案,使用Maclaurin级数直到第30项 我想到了用列表来表示1和-1的交替序列,将x提升为奇数,以及奇数的阶乘。然后,我将前两个列表相乘,最后一个列表相除。到目前为止,我只写了以下内容: oddl = [1,3..] powerl x = map (x^) oddl factorial 0 = 1 factorial x = factorial (x - 1) * x factl = m
oddl = [1,3..]
powerl x = map (x^) oddl
factorial 0 = 1
factorial x = factorial (x - 1) * x
factl = map factorial oddl
alterl = scanl (*) (-1) [-1,-1..]
sined x = zipWith (*) (powerl x) alterl
sinex x = zipWith (/) sined factl
sinf x = foldl (+) (take 30 (sinex x))
然后在ghci
中,我将输入sinf 3.14
,但在加载后输入之前,我得到以下信息:
exert.hs:31:8:
No instance for (Enum t0)
arising from the arithmetic sequence ‘1, 3 .. ’
The type variable ‘t0’ is ambiguous
Relevant bindings include oddl :: [t0] (bound at exert.hs:31:1)
Note: there are several potential instances:
instance forall (k :: BOX) (s :: k). Enum (Data.Proxy.Proxy s)
-- Defined in ‘Data.Proxy’
instance Integral a => Enum (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
instance Enum Ordering -- Defined in ‘GHC.Enum’
...plus 8 others
In the expression: [1, 3 .. ]
In an equation for ‘oddl’: oddl = [1, 3 .. ]
exert.hs:31:9:
No instance for (Num t0) arising from the literal ‘1’
The type variable ‘t0’ is ambiguous
Relevant bindings include oddl :: [t0] (bound at exert.hs:31:1)
Note: there are several potential instances:
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Double -- Defined in ‘GHC.Float’
...plus three others
In the expression: 1
In the expression: [1, 3 .. ]
In an equation for ‘oddl’: oddl = [1, 3 .. ]
exert.hs:32:18:
Could not deduce (Integral t0) arising from a use of ‘^’
from the context (Num b)
bound by the inferred type of powerl :: Num b => b -> [b]
at exert.hs:32:1-24
The type variable ‘t0’ is ambiguous
Note: there are several potential instances:
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
In the first argument of ‘map’, namely ‘(x ^)’
In the expression: map (x ^) oddl
In an equation for ‘powerl’: powerl x = map (x ^) oddl
exert.hs:35:13:
No instance for (Eq t0) arising from a use of ‘factorial’
The type variable ‘t0’ is ambiguous
Relevant bindings include factl :: [t0] (bound at exert.hs:35:1)
Note: there are several potential instances:
instance (Eq a, Eq b) => Eq (Either a b)
-- Defined in ‘Data.Either’
instance forall (k :: BOX) (s :: k). Eq (Data.Proxy.Proxy s)
-- Defined in ‘Data.Proxy’
instance (GHC.Arr.Ix i, Eq e) => Eq (GHC.Arr.Array i e)
-- Defined in ‘GHC.Arr’
...plus 28 others
In the first argument of ‘map’, namely ‘factorial’
In the expression: map factorial oddl
In an equation for ‘factl’: factl = map factorial oddl
exert.hs:38:23:
Couldn't match expected type ‘[t0]’
with actual type ‘Integer -> [Integer]’
Relevant bindings include
sinex :: t -> [t0] (bound at exert.hs:38:1)
Probable cause: ‘sined’ is applied to too few arguments
In the second argument of ‘zipWith’, namely ‘sined’
In the expression: zipWith (/) sined factl
exert.hs:39:16:
Could not deduce (Num [t0]) arising from a use of ‘+’
from the context (Foldable t)
bound by the inferred type of
sinf :: Foldable t => t1 -> t [t0] -> [t0]
at exert.hs:39:1-38
The type variable ‘t0’ is ambiguous
Relevant bindings include
sinf :: t1 -> t [t0] -> [t0] (bound at exert.hs:39:1)
In the first argument of ‘foldl’, namely ‘(+)’
In the expression: foldl (+) (take 30 (sinex x))
In an equation for ‘sinf’: sinf x = foldl (+) (take 30 (sinex x))
Failed, modules loaded: none.
这么多信息。哇!
我不知道自己做错了什么,甚至不知道从哪里开始阅读信息。
有人能解释一下吗?实际上,作为一个初学者,我很好奇Haskell的错误是什么,以及是什么阻止了它的工作
编辑:添加类型签名和缺少的参数后。
oddl :: [Integer]
oddl = [1,3..]
powerl :: Integer -> [Integer]
powerl x = map (x^) oddl
factorial 0 = 1
factorial x = factorial (x - 1) * x
factl :: [Integer]
factl = map factorial oddl
alterl = scanl (*) (-1) [-1,-1..]
sined x = zipWith (*) (powerl x) alterl
sinex x = zipWith (/) (sined x) factl
sinf x = foldl (+) (take 30 (sinex x))
现在我得到一个较短的错误:
exert.hs:41:19:
No instance for (Fractional Integer) arising from a use of ‘/’
In the first argument of ‘zipWith’, namely ‘(/)’
In the expression: zipWith (/) (sined x) factl
In an equation for ‘sinex’: sinex x = zipWith (/) (sined x) factl
exert.hs:42:16:
Could not deduce (Num [Integer]) arising from a use of ‘+’
from the context (Foldable t)
bound by the inferred type of
sinf :: Foldable t => Integer -> t [Integer] -> [Integer]
at exert.hs:42:1-38
In the first argument of ‘foldl’, namely ‘(+)’
In the expression: foldl (+) (take 30 (sinex x))
In an equation for ‘sinf’: sinf x = foldl (+) (take 30 (sinex x))
Haskell中的数字与类型和类型推断有很多关系,因此对于初学者来说,它们可能很棘手。不允许使用
/
运算符对整数进行除法(有`div`
用于截断整数除法)。如何使常数成为整数也可能相当棘手,因为这取决于它的使用方式(稍后!)1。但您需要了解的主要内容是fromIntegral
函数,它将整数转换为任何其他数值类型
ghci> let x = 10 :: Integer
ghci> x / 5
<interactive>:6:1: error:
• No instance for (Fractional Integer) arising from a use of ‘/’
• In the expression: x / 5
In an equation for ‘it’: it = x / 5
ghci> fromIntegral x / 5
2.0
该oddl
必须是整数列表<代码>(*)返回与其参数相同的类型(必须是相同的类型),因此我们从
powerl x = map (x^) oddl
factorial x = factorial (x - 1) * x
factorial返回与其参数相同的类型,因此
factl = map factorial oddl
还必须是整数列表。那么我们有
sinex x = zipWith (/) sined factl
它现在将整数作为
(/)
的参数,这是不合法的 编辑后,查看第一个错误:
No instance for (Fractional Integer) arising from a use of ‘/’
(/)
的类型为:
(/) :: Fractional a => a -> a -> a
因此,它接受两个a
类型的值,它们必须是分数
,并返回同一类型a
的结果Integer
不是fractal
——这里有整数除法函数div
和quot
(以及它们的余数对应项mod
和rem
),但这不是您想要的,因为您想要的是分数结果。解决方案是使用from integral
将整数参数转换为分数类型,例如Double
:
fromIntegral :: (Num b, Integral a) => a -> b
fromIntegral (x :: Integer) :: Double -- or ‘… :: Float’
例如,您可以编写sum xs/from integral(length xs)
来获得Double
列表的平均值
第二个错误:
Could not deduce (Num [Integer]) arising from a use of ‘+’
源于此表达式:
foldl (+) (take 30 (sinex x))
foldl
接受三个参数:缩减函数、起始值和输入容器;您试图将容器作为起始值传递,因此foldl
尝试对未定义的整数列表调用+
。您可能需要foldl(+)0
或sum
。这里有一个更合理的方法来编写所有内容:
sinf :: Double -> Double
sinf x = sum $ take 30
[ sign * power / fact
| (sign, power, fact) <- zip3
(iterate negate 1)
(oddEntries $ iterate (*x) 1)
(oddEntries factorials) ]
where factorials :: [Double]
factorials = scanl (*) 1 [1..]
oddEntries :: [a] -> [a]
oddEntries (_:x:xs) = x : oddEntries xs
oddEntries _ = []
这里,typechecker自动做正确的事情,并为阶乘列表(以及符号列表)选择类型Double
,因为上下文需要Double
。(但为了便于阅读,最好还是给它起一个本地名称和签名。)
实际上,您只需在零附近的小范围内使用Maclaurin级数,并利用周期性定义实轴其余部分的函数:
sinf :: Double -> Double
sinf x = sum $ take 30
[ sign * power / fact
| (sign, power, fact) <- zip3
(iterate negate 1)
(oddEntries $ iterate (*x') 1)
(oddEntries factorials) ]
where factorials :: [Double]
factorials = scanl (*) 1 [1..]
x' = x - 2*pi*fromIntegral (round $ x/(2*pi))
sinf::Double->Double
sinf x=总计$30
[签名*权力/事实]
|(签名、权力、事实)始终写出类型签名。(这可能不会解决您的问题,但它肯定会大大降低错误消息的神秘性。)我可能不想在这里问这个问题,但类型签名到底是什么?那一行是“:”?@user3076623是的,完全正确。不相关,但是alterl=iterate-negate 1
感觉更好concise@RegisKuckaertz我认为,alterl=cycle[1,-1]
更清楚。但是fromIntegral只适用于单个值,对吗?@user3076623,是的,但它是一个常规函数,所以你可以映射它。我可能更愿意做一个小助手,尽管divInts x y=fromIntegral x/fromIntegral y
来进行压缩。所以它就像“sined x=map(fromIntegral)(zipWith(*)(powerl x)alterl)“?@user3076623,在我看来是正确的(用integral中的多余参数进行模运算)事实上,你的建议是有效的!我的意思是第一个。
$ ghci wtmpf-file3770.hs
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main ( wtmpf-file3770.hs, interpreted )
Ok, 1 module loaded.
*Main> :m +Graphics.Dynamic.Plot.R2
*Main Graphics.Dynamic.Plot.R2> plotWindow [legendName "sin" $ continFnPlot sin, legendName "sinf" $ continFnPlot sinf]
sinf :: Double -> Double
sinf x = sum $ take 30
[ sign * power / fact
| (sign, power, fact) <- zip3
(iterate negate 1)
(oddEntries $ iterate (*x') 1)
(oddEntries factorials) ]
where factorials :: [Double]
factorials = scanl (*) 1 [1..]
x' = x - 2*pi*fromIntegral (round $ x/(2*pi))