Haskell 在这个动态编程示例中,如何使fromList变懒?
上述情况并不完全正确。必须记住,所有的Haskell 在这个动态编程示例中,如何使fromList变懒?,haskell,dynamic-programming,lazy-evaluation,memoization,continuations,Haskell,Dynamic Programming,Lazy Evaluation,Memoization,Continuations,上述情况并不完全正确。必须记住,所有的fs都是独立的 go x f y = (x + y) : f x go x f y = (x + y) : f x go x f y = (x + y) : f x 此外,为了清晰起见,将lambda分开也应该是有指导意义的 go x f'' y = (x + y) : f'' x go x f' y = (x + y) : f' x go x f y = (x + y) : f x 现在折叠从顶部开始。最顶端的语句的计算结果为 go x f'' = \
f
s都是独立的
go x f y = (x + y) : f x
go x f y = (x + y) : f x
go x f y = (x + y) : f x
此外,为了清晰起见,将lambda分开也应该是有指导意义的
go x f'' y = (x + y) : f'' x
go x f' y = (x + y) : f' x
go x f y = (x + y) : f x
现在折叠从顶部开始。最顶端的语句的计算结果为
go x f'' = \y -> (x + y) : f'' x
go x f' = \y -> (x + y) : f' x
go x f = \y -> (x + y) : f x
这减少到:
go 3 (\_ -> []) = \y -> (3 + y) : (\_ -> []) 3
go 2 (\y -> (3 + y) : []) = \y -> (2 + y) : (\y -> (3 + y) : []) 2
go 1 (\y -> (2 + y) : 5 : []) = \y -> (1 + y) : (\y -> (2 + y) : 5 : []) 1
结果是上面未完成的lambda。现在,fold计算第二个语句
go 3 (\_ -> []) = (\y -> (3 + y) : [])
go 2 (\y -> (3 + y) : []) = (\y -> (2 + y) : 5 : [])
go x f'' = \y -> (x + y) : f'' (2*y+1)
go x f' = \y -> (x + y) : f' (2*y+1)
go x f = \y -> (x + y) : f (2*y+1)
这减少到:
go 3 (\_ -> []) = \y -> (3 + y) : (\_ -> []) 3
go 2 (\y -> (3 + y) : []) = \y -> (2 + y) : (\y -> (3 + y) : []) 2
go 1 (\y -> (2 + y) : 5 : []) = \y -> (1 + y) : (\y -> (2 + y) : 5 : []) 1
折叠到最后一句话
go 3 (\_ -> []) = (\y -> (3 + y) : [])
go 2 (\y -> (3 + y) : []) = (\y -> (2 + y) : 5 : [])
go x f'' = \y -> (x + y) : f'' (2*y+1)
go x f' = \y -> (x + y) : f' (2*y+1)
go x f = \y -> (x + y) : f (2*y+1)
这减少到:
go 3 (\_ -> []) = \y -> (3 + y) : (\_ -> []) 3
go 2 (\y -> (3 + y) : []) = \y -> (2 + y) : (\y -> (3 + y) : []) 2
go 1 (\y -> (2 + y) : 5 : []) = \y -> (1 + y) : (\y -> (2 + y) : 5 : []) 1
将应用折叠外的0,并将最终lambda减小为
go 1 (\y -> (2 + y) : 5 : []) = \y -> (1 + y) : 3 : 5 : []
这只是开始。当fx
替换为fy
时,情况变得更加有趣
这里有一个与前一个类似的程序
1 : 3 : 5 : []
最重要的声明
go 3 (\_ -> []) = (\y -> (3 + y) : [])
go 2 (\y -> (3 + y) : []) = (\y -> (2 + y) : 5 : [])
go x f'' = \y -> (x + y) : f'' (2*y+1)
go x f' = \y -> (x + y) : f' (2*y+1)
go x f = \y -> (x + y) : f (2*y+1)
中间声明:
go 3 (\_ -> []) = \y -> (3 + y) : (\_ -> []) (2*y+1)
go 2 (\y -> (3 + y) : (\_ -> []) (2*y+1)) = \y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)
最后一句话:
go 3 (\_ -> []) = \y -> (3 + y) : (\_ -> []) (2*y+1)
go 2 (\y -> (3 + y) : (\_ -> []) (2*y+1)) = \y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)
注意表达式是如何建立的,因为不能应用y
s。只有在插入0之后,才能计算整个表达式
go 1 (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) = \y -> (1 + y) : (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) 2*y+1
由于评估的顺序,有一个累积
编辑:所以
(\y -> (1 + y) : (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) 2*y+1) 1
2 : (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) 3
2 : 5 : (\y -> (3 + y) : (\_ -> []) (2*y+1)) 7
2 : 5 : 10 : (\_ -> []) 15
2 : 5 : 10 : []
go(candy,score)fcs=(candy',score):fccandy'score
其中candy'=最大candy$如果s<分数,则c+1,否则1
事实上,在每次迭代中,上面的代码在列表中传递了3次
首先,foldr必须在列表的后面,然后才能开始。然后,由于candi'
依赖于s
和c
变量,这些变量不能立即应用,因此需要建立延续性,如最后一个示例中所示
然后,当两个0
0
在折叠结束时输入时,整个过程才得到评估
go 1 (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) = \y -> (1 + y) : (\y -> (2 + y) : (\y -> (3 + y) : (\_ -> []) (2*y+1)) (2*y+1)) 2*y+1
这有点难以解释。您所链接的问题有一个干净的Haskell解决方案,使用右折叠。换句话说,通过使用更实用的样式,您可以跳过对lazy fromList、Memonization和所有这些的担忧 这样做的目的是维护一个
(candy,score)
对的列表,其中candy
最初对所有人都是零(在下面的代码中重复0
)。然后从左向右移动一次,如果此项得分超过之前的值,则增加candy
值:
go (candy, score) f c s = (candy', score): f candy' score
where candy' = max candy $ if s < score then c + 1 else 1
--s是分数,c是之前那个家伙的糖果
--如果s
再朝另一个方向做同样的事情:
-- s is the score and c is the candy of the guy before
-- if s < score then this guy should get at least c + 1 candies
candy' = max candy $ if s < score then c + 1 else 1
import Control.Monad(复制项)
导入控件。应用程序(())
求解::[Int]->Int
求解=求和。地图fst。环颠倒环拉链(重复0)
哪里
循环cs=foldr go(\\\\\>[])cs 0
去(糖果,得分)f c s=(糖果,得分):f糖果,得分
其中candy'=最大candy$如果s<分数,则c+1,否则1
main=do
n>=打印
这将线性执行,并通过HackerRank上的所有测试。您所链接的问题有一个干净的Haskell解决方案,使用右折叠。换句话说,通过使用更实用的样式,您可以跳过对lazy fromList、Memonization和所有这些的担忧 这样做的目的是维护一个
(candy,score)
对的列表,其中candy
最初对所有人都是零(在下面的代码中重复0
)。然后从左向右移动一次,如果此项得分超过之前的值,则增加candy
值:
go (candy, score) f c s = (candy', score): f candy' score
where candy' = max candy $ if s < score then c + 1 else 1
--s是分数,c是之前那个家伙的糖果
--如果s
再朝另一个方向做同样的事情:
-- s is the score and c is the candy of the guy before
-- if s < score then this guy should get at least c + 1 candies
candy' = max candy $ if s < score then c + 1 else 1
import Control.Monad(复制项)
导入控件。应用程序(())
求解::[Int]->Int
求解=求和。地图fst。环颠倒环拉链(重复0)
哪里
循环cs=foldr go(\\\\\>[])cs 0
去(糖果,得分)f c s=(糖果,得分):f糖果,得分
其中candy'=最大candy$如果s<分数,则c+1,否则1
main=do
n>=打印
它的性能是线性的,并且通过了HackerRank上的所有测试。好吧,关于我自己在顶部的问题,可能让事情变得懒惰的方法是只使用一个列表(列表列表列表或列表向量)。上面不可能让事情变得懒惰的原因是,映射类型在值上是懒惰的,在键上是严格的 更重要的是,我的分析,褶皱基本上是做两次通过是完全正确的。这些构建的延续在反向执行时的方式一开始完全让我感到困惑,但我已经修改了@behzad.nouri代码,使其只处理一个循环
import Control.Monad (replicateM)
import Control.Applicative ((<$>))
solve :: [Int] -> Int
solve = sum . map fst . loop . reverse . loop . zip (repeat 0)
where
loop cs = foldr go (\_ _ -> []) cs 0 0
go (candy, score) f c s = (candy', score): f candy' score
where candy' = max candy $ if s < score then c + 1 else 1
main = do
n <- read <$> getLine
solve . fmap read <$> replicateM n getLine >>= print
modulemain其中
导入控制.Monad(复制项)
导入控件。应用程序(())
导入调试跟踪
求解::[Int]->Int
求解=求和。环
哪里
循环::[Int]->[Int]
循环=(\(\,x)->x0)。foldr go(0,0,\\\\\\>[]))
围棋:Int->(Int,Int,Int->Int->[Int])->(Int,Int,Int->Int->[Int])
围棋得分(坎迪普、得分、f)=
允许
candyP'=如果得分p
允许
candy'=最大candyP'$如果scoreN=打印
以上内容通过了所有测试,没有问题,这是上述分析正确性的有力证明。好吧,关于我自己在顶部的问题,可能让事情变得懒惰的方法就是只使用一个列表(列表列表列表或列表向量)上面不可能使其变为惰性的原因是,映射类型在值中是惰性的,在键中是严格的 更重要的是,我的分析,褶皱基本上是做两次通过是完全正确的。那些建立起来的延续方式正在被改变