我几天前开始使用Haskell。 我有以下代码片段(递归函数):
totaltime t [x] = 0
totaltime t route = tbd + totaltime (t+tbd) (tail(route))
where tbd = timebetweendepartures (fst(route!!0)) (fst(route!!1)) t (snd(route!!1))
“route”是一个元组列表,例如:[(3,1),(1,2),(5,2),(2,1)]
我正在尝试做的是在函数开始执行它应该执行的操作之前将(0,0)添加到路径。
因此,如果参数路由作为[(3,1),(1,2),(5,2),(2,1)]传递,那么函数应该接收它为[(0,0), (3,1),(1,2),(5,2),(2,1)]
我可以做totaltime t ((0,0):route)
,但由于该函数是递归的,因此无法按预期工作。
非常感谢您的想法!
答案 0 :(得分:7)
简短回答:您可以将函数totaltime
置于where
子句范围内,并公开另一个以(0,0)
为前缀的函数:
totaltime t l = tt t ((0,0):l)
where tt t [x] = 0
tt t route = tbd + tt (t+tbd) (tail(route))
where tbd = timebetweendepartures (fst(route!!0)) (fst(route!!1)) t (snd(route!!1))
但话虽如此,代码非常不优雅,可能不安全:
!!0
和!!1
这些函数不是 total 。此外,您调用fst
和snd
并不是很优雅。我们可以在条款的头部引入模式,通常使它更优雅,更容易理解。因此,我们可以将tt
函数重写为:
tt t [] = ... # create a case for the empty list
tt t [x] = 0
tt t ((x0,_):xys@((x1,y1):_)) = tbd + tt (t+tbd) xys
where tbd = timebetweendepartures x0 x1 t y1
现在我们可以使用它:
totaltime t l = tt t ((0,0):l)
where tt t [] = ... # create a case for the empty list
tt t [x] = 0
tt t ((x0,_):xys@((x1,y1):_)) = tbd + tt (t+tbd) xys
where tbd = timebetweendepartures x0 x1 t y1
当然在这种情况下,永远不可能处理空列表,因为totaltime
预先(0,0)
我们保证初始调用是一个至少有一个元素的调用,而我们在直接尾部执行递归,这意味着列表一次减少一个。
然而,我们仍然可以通过使用三个句子来改进功能:t
变量;列表的头部,列表的尾部,并将其重写为:
totaltime t = tt t (0,0)
where tt _ _ [] = 0
tt t (x0,_) (xyh@(x1,y1):xyt) = tbd + tt (t+tbd) xyh xyt
where tbd = timebetweendepartures x0 x1 t y1
现在代码在语法上是完全的,而且它可以提高效率(因为我们避免解压缩列表的某些部分两次。
我们仍然可以改进代码。请注意,我们只使用列表头部的第一个元素(我们不使用y0
变量)。所以我们可以省略打包和解压缩并将其重写为:
totaltime t = tt t 0
where tt _ _ [] = 0
tt t x0 ((x1,y1):xyt) = tbd + tt (t+tbd) x1 xyt
where tbd = timebetweendepartures x0 x1 t y1
现在我们可以节省解包元组,并且更清楚我们的工作。
答案 1 :(得分:4)
您可以将该功能包装到"入口点"执行外部接收参数预处理的函数:
totaltime t route =
totaltime' t ((0,0):route)
where
totaltime' t [x] = 0
totaltime' t route = .....