代码之家  ›  专栏  ›  技术社区  ›  Bercovici Adrian

褶皱中的种子分解类型

  •  1
  • Bercovici Adrian  · 技术社区  · 6 年前

    我有以下问题:

    我想计算第一个的和 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 ,如何将其放置为模式匹配而不是其数据构造函数?

    在我的例子中, 福德尔 接受 动静脉畸形 哪个是 seed 以及列表中的一个元素。

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   chi    6 年前

    一些可能的解决方案:

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

    (使用) let foo .. in .. 也是可能的)

        2
  •  1
  •   sshine    6 年前

    自从 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 (哈斯克尔)。