[英]Decomposing type as seed in fold
I have the following problem: 我有以下问题:
I want to calculate the sum of the first n
numbers and keep the count of each added number on every iteration. 我想计算前n
个数的总和,并在每次迭代时保持每个添加数的计数。 Therefore i defined a type: 因此我定义了一个类型:
data Avg = Avg { sum :: Int, count :: Int }
I need to use a seed of type Avg
in a foldl'
but i need it decomposed inside the aggregator function: 我需要在foldl'
使用Avg
类型的种子,但我需要在聚合器函数内分解它:
bang :: [Int] -> IO ()
bang ls@(x:xs) = printAvg $ foldl ' (\x y -> (x sum+y count+1) ) (Avg 0 0) ls
printAvg :: Avg -> IO ()
printAvg av = putStrLn . show (fromIntegral $ sum av / fromIntegral $ count av)
So my question is: 所以我的问题是:
Given a type data T = T { a :: Int, b :: Int }
and given a variable myvar
of type T
, how can I place it for pattern matching instead of its data constructor? 给定类型data T = T { a :: Int, b :: Int }
并给出类型为T
的变量myvar
,如何将其放置为模式匹配而不是其数据构造函数?
In my example the foldl'
takes an Avg
which is the seed
and one element from the list. 在我的例子中, foldl'
取一个Avg
,它是seed
和列表中的一个元素。
I need (\\x y-> (x sum+y count+1))
instead of (\\x y-> (Avg sum+y count+1))
. 我需要(\\x y-> (x sum+y count+1))
而不是(\\x y-> (Avg sum+y count+1))
。
A few possible solutions: 一些可能的解决方案:
(\ (Avg s c) y -> Avg (s + y) (c + 1))
-- equivalent to the longer
(\ x y -> case x of Avg s c -> Avg (s + y) (c + 1))
-- mentioning the fields name explicitly
(\ Avg{sum=s, count=c} y -> Avg (s + y) (c + 1))
-- using the RecordWildCards extension
(\ Avg{..} y -> Avg (sum + y) (count + 1))
-- using the two projections
(\ x y -> Avg (sum x + y) (count x + 1))
or even, adapting your code 甚至,调整你的代码
bang::[Int]->IO()
bang ls@(x:xs) = printAvg $ foldl' foo (Avg 0 0) ls
where
foo (Avg s c) y = Avg (s + y) (c+ 1)
(using let foo .. in ..
is also possible) (使用let foo .. in ..
也是可能的)
Since data Avg = Avg { sum :: Int, count :: Int }
is isomorphic to (Int, Int)
, you could also fold with a tuple: 由于data Avg = Avg { sum :: Int, count :: Int }
与(Int, Int)
同构,因此您也可以使用元组折叠:
average :: Fractional r => [Int] -> r
average = uncurry (/) . foldr (\x (sum, count) -> (sum+x, count+1)) (0,0)
bang :: [Int] -> IO ()
bang = putStrLn . show . average
And if you want to keep the average running, you could use a newtype
wrapper: 如果你想保持平均运行,你可以使用newtype
包装器:
newtype Count = Count (Int, Int)
accumulate :: [Int] -> Count
accumulate = foldr accum (Count (0, 0))
where
accum :: Int -> Count -> Count
accum x (Count (sum, count)) = Count (sum+x, count+1)
average :: Fractional r => Count -> r
average (Count (x, y)) = x / y
bang :: [Int] -> IO ()
bang = putStrLn . show . average . accumulate
You might risk overflows in both cases. 在这两种情况下,您都可能面临溢出风险
Consider finding a moving average (Haskell). 考虑找一个移动平均线 (Haskell)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.