分解类型作为种子折叠

时间:2018-07-02 11:41:34

标签: haskell

我有以下问题:

我想计算前n个数字的总和,并在每次迭代中保留每个加数的计数。因此,我定义了一个类型:

data Avg = Avg { sum :: Int, count :: Int }

我需要在Avg中使用类型为foldl'的种子,但是我需要在聚合函数内部对其进行分解:

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)

所以我的问题是:

给出类型data T = T { a :: Int, b :: Int }并给定类型myvar的变量T,我该如何放置它以进行模式匹配而不是其数据构造函数?

在我的示例中,foldl'包含一个Avg和一个seed以及列表中的一个元素。

我需要(\x y-> (x sum+y count+1))而不是(\x y-> (Avg sum+y count+1))

2 个答案:

答案 0 :(得分:2)

一些可能的解决方案:

    protected $fields = [
        'type' => [
            'type' => 'anomaly.field_type.select',
            'config' => [
                'options'       => ['foo' => 'Foo', 'bar' => 'Bar'],
                'mode'          => 'dropdown'
            ]
        ]
    ];

甚至修改您的代码

(\ (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))

(也可以使用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)

答案 1 :(得分:1)

由于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

如果要保持平均运行,可以使用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

在这两种情况下,您都可能会有溢出的风险。

考虑找到一个moving average(哈斯克尔)。