如何获得与向量一起使用的通用平均值以在 Haskell 中编译?

How to get a generic average that works with vectors to compile in Haskell?

我试过了:

import Data.VectorSpace     -- ^/
import Data.AdditiveGroup   -- sumV
import Data.Foldable        -- length

avg :: (Foldable f, VectorSpace a) => f a -> a
avg xs = sm ^/ sz    -- could be just ^*(1/sz)
 where sm = sumV xs
       sz = fromIntegral (length xs)

并得到:

Distancesumcurves.hs:11:10: error:
    • Could not deduce (Fractional (Scalar a))
        arising from a use of ‘^/’
      from the context: (Foldable f, VectorSpace a)
        bound by the type signature for:
                   avg :: (Foldable f, VectorSpace a) => f a -> a
        at Distancesumcurves.hs:10:1-46
    • In the expression: sm ^/ sz
      In an equation for ‘avg’:
          avg xs
            = sm ^/ sz
            where
                sm = sumV xs
                sz = fromIntegral (length xs)

Distancesumcurves.hs:13:13: error:
    • Could not deduce (Num (Scalar a))
        arising from a use of ‘fromIntegral’
      from the context: (Foldable f, VectorSpace a)
        bound by the type signature for:
                   avg :: (Foldable f, VectorSpace a) => f a -> a
        at Distancesumcurves.hs:10:1-46
    • In the expression: fromIntegral (length xs)
      In an equation for ‘sz’: sz = fromIntegral (length xs)
      In an equation for ‘avg’:
          avg xs
            = sm ^/ sz
            where
                sm = sumV xs
                sz = fromIntegral (length xs)

当然我可以专门为向量写一个,然后继续我的生活,但是 Haskell 的通用特性有什么意义呢?用一种不那么迂腐的语言我已经完成了它,它会工作得很好,而且它是可重用的。在 Haskell 我必须在这里写一个问题或回归到代码重复。我认为这是语言的失败。

这不是我第一次对 Haskell 泛型感到沮丧。我已经超过了 Graham Hutton 在 Haskell 中编程一书的水平。对我来说,下一个 step/book/article 应该是什么?这样当我知道我想要什么并且它是正确的时,我就不会与编译器争论。在这种情况下,我缺乏的只是语言技术技能。如果我错了,请随时纠正我。


编辑:

似乎在上下文中有效

approximateCurve :: [Point] -> Path
approximateCurve pts = [] -- TODO
 where center = avg pts
       avg vs = (sum vs) ^/ (fromIntegral (length vs))
       sum = foldr (^+^) (0,0)

在这种情况下,我会添加错误消息中建议的附加约束,以获得 avg :: (Foldable f, VectorSpace a, Fractional (Scalar a)) => f a -> a

Fractional表示Num,不用说Num。如果你添加它也没有坏处 - 该功能并没有变得不那么通用。

就一般建议而言,我认为在类型错误的指导下编写大量泛型函数是最好的方法。通常添加建议的约束就足够了;其他时候你真的想要更通用的签名,并且需要弄清楚哪个函数带来了不需要的约束。