Haskell 性能问题

Haskell 性能问题,haskell,memoization,Haskell,Memoization,我正在处理时间序列,type TSeries=[(Day,Double)],但需要将第一个Day元素转换为Double以进行进一步处理(例如绘图等) 将日期范围映射到相应的双范围[lobound,upbound],其中最早的日期映射到lobound,最晚的日期映射到upbound,这是一个基本转换。为了实现它,我首先需要得到日期范围的最小值和最大值。我遇到了性能问题,但我不确定确切的原因以及如何解决它 以下是代码(不假定时间序列已排序): modulemain其中 导入数据。时间(天,从公历开始

我正在处理时间序列,
type TSeries=[(Day,Double)]
,但需要将第一个
Day
元素转换为Double以进行进一步处理(例如绘图等)

将日期范围映射到相应的双范围[lobound,upbound],其中最早的日期映射到lobound,最晚的日期映射到upbound,这是一个基本转换。为了实现它,我首先需要得到日期范围的最小值和最大值。我遇到了性能问题,但我不确定确切的原因以及如何解决它

以下是代码(不假定时间序列已排序):

modulemain其中
导入数据。时间(天,从公历开始,从公历开始)
类型t系列=[(天,双)]
--时间序列到(双,双)映射函数
toDbl::(日->双倍)->t系列->[(双倍,双倍)]
toDbl mapX ts=map(\(d,x)->(mapX d,x))ts
--日到双倍映射功能-快速
mapDays1::(天,双倍)->(天,双倍)->天->双倍
mapDays1(d0,x0)(d1,x1)d=((从整数$diffDays d d0)*x1+(从整数$diffDays d1 d)*x0)/diff10
其中diff10=from积分$diffDays d1 d0
--日到双倍映射功能-慢速
mapDays2::t序列->双倍->双倍->日->双倍
mapDays2 ts x0 x1 d=mapDays1(d0,x0)(d1,x1)d
其中d0=最小$map fst ts
d1=最大$map fst ts
--时间序列示例
func::Int->Double
func d=sin$pi/14*(来自积分d)

ts=[(fromgorian y m d,func d)| y问题确实与记忆有关。问题是调用
mapDays1
mapDays2
,而不传递它们的所有参数,因此这些调用只创建thunk

问题 这意味着thunk只能在
map
内部完成,因此对
mapDays2
的不同调用不能共享
d0=最小$map fst ts
d1=最大$map fst ts
的结果,并且每次都会重新评估最大和最小值
d0
d1
取决于最后一个
日期
参数,在这种情况下,不每次重新计算
d0
d1
是不正确的

相比之下,
mindate=minimum$map fst ts
maxdate=maximum$map fst ts
只需计算一次就可以了

正在修复
mapDays2
虽然我们喜欢假装
fxy=e
fx=\y->e
相同,但它不是隐藏的。您希望GHC在传递除最后一个参数外的所有参数时避免发出砰砰声。只需将
d
移到等号上。然后,返回的函数将只计算一次
d0
d1

-- Day to Double mapping function - slow
mapDays2 :: TSeries -> Double -> Double -> Day -> Double
mapDays2 ts x0 x1 = \d -> mapDays1 (d0,x0) (d1,x1) d
    where d0 = minimum $ map fst ts
          d1 = maximum $ map fst ts

谢谢,它确实工作得很好。解决方案非常微妙;它如何防止GHC过早地发出Thunk?即使我们假装Curry使所有函数只接受一个参数,但它实际上并不是这样工作的(这将是非常低效的).GHC生成的函数包含您指定的任意多个参数,并使用thunks计算出所有隐藏的参数。因此,接受4个参数的函数与接受3个参数并返回接受一个参数的函数之间存在区别。“它不隐藏”这里的行为可能是由于内联和随后的简单优化(只有在语法上完全应用右侧的函数才能内联),而不是ghc如何处理函数的更可怕的东西。
-- Day to Double mapping function - slow
mapDays2 :: TSeries -> Double -> Double -> Day -> Double
mapDays2 ts x0 x1 = \d -> mapDays1 (d0,x0) (d1,x1) d
    where d0 = minimum $ map fst ts
          d1 = maximum $ map fst ts