在Haskell中演示惰性评估?
这是我的一个家庭作业中的一个问题,我一直无法回答。这是通过演示Haskell编译器解释器是如何工作的,来对Haskell代码进行推理的?执行程序 我被赋予了一些不同的功能在Haskell中演示惰性评估?,haskell,lazy-evaluation,Haskell,Lazy Evaluation,这是我的一个家庭作业中的一个问题,我一直无法回答。这是通过演示Haskell编译器解释器是如何工作的,来对Haskell代码进行推理的?执行程序 我被赋予了一些不同的功能 -- built-in take :: Int -> [a] -> [a] take 0 _ = [] take n (x:xs) = x : (take (n - 1) xs) -- exchanging entries exchange :: [a] -> [a] exchange [x,y]
-- built-in
take :: Int -> [a] -> [a]
take 0 _ = []
take n (x:xs) = x : (take (n - 1) xs)
-- exchanging entries
exchange :: [a] -> [a]
exchange [x,y] = [y,x]
exchange (x:y:xs) = (y:x:(exchange xs))
-- picking even numbered entries
evens :: [a] -> [a]
evens [x,y] = [x]
evens (x:_:xs) = x:(evens xs)
-- first four numbers repeated
first_four :: [Int]
first_four = 1:2:3:4:first_four
现在我必须假装是编译器来演示对惰性计算的理解。通过分解此语句的执行方式
> take 5 (evens (exchange first_four))
[2,4,2,4,2]
我得到了帮助开始的前几行
take 5 (evens (exchange first_four)) =
take 5 (evens (exchange (1:2:3:4:first_four))) =
take 5 (evens (2:1:(exchange (3:4:first_four)))) =
...
我想了解懒惰评估是如何工作的,这样我就可以回答这个问题了 将您的定义视为重新编写的方程式,并始终在过渡实体发挥作用时对其进行唯一命名:
take 5 (evens (exchange first_four))
-- match: take 0 .... = .... ? FAIL
-- match: take n (x:xs) = .... ? SUCCESS
n1 = 5
(x1:xs1) ?= evens (exchange first_four)
-- evens [x,y] = ....
[x2,y2] ?= exchange first_four
-- exchange [x,y] = ....
[x3,y3] ?= first_four
......
操作是机械的。这里的懒惰意味着,我们从左到右,从不试图过早地找出表达式的值,只在我们实际需要模式匹配某些定义时才这样做
以下是我命名临时实体的意思:
take 5 (evens (exchange first_four)) =
take 5 xs where xs = evens (exchange first_four)
(x1:xs1) ?= xs -- <---- THIS
= evens (exchange first_four)
= evens ys where ys = exchange first_four
[x2,y2] ?= ys -- <--- AND THIS
. . = exchange first_four
. . -- ^^ <--- already named
. . [x3,y3] ?= first_four
. . FAIL
. . (x3:y3:xs3) ?= first_four
. . = 1:2:3:4:first_four
. . SUCCESS: x3=1
. . y3=2
. . xs3=3:4:first_four
. . ys = y3:x3:exchange xs3 !
. . [] ?= exchange xs3
. = ...
. FAIL
(x2:_:xs2) ?= ys
SUCCESS: x2=y3
xs2=...
我相信你现在能完成这件事
举例来说,这里的交换从程序上看,它是一个流转换器,可以从输入中提取元素;查看它的输入是否有一个准备好拉取的元素;并将一个元素推入其输出
exchange:
pull(X) ... on_fail: ERROR
pull(Y) ... on_fail: ERROR
peek ... on_fail: push(Y); push(X); STOP
push(Y); push(X)
LOOP
来到这里之前,你有没有阅读过网上已有的大量资源?@BartekBanachewicz YesI曾在这里为Haskell函数写过一个详细的评估链:也许这会对你有所帮助。如果你真的要解释懒惰的部分,我认为这里的第一个评估步骤不是很诚实…@Carsten确实,这些行完全错了。我不知道过渡实体是什么意思,比如x1和xs1,等等。当需要时,强制计算表达式值的是需要模式匹配它。与take一样,take 0…=。。。与呼叫不匹配,需要5。。。;所以我们继续讨论take定义中的下一个子句,并尝试匹配调用take 5。。。取nx:xs=。。。。因此,通过注册n=5,n与5匹配。接下来,我们必须看看埃文斯是否。。。与x:xs匹配,但我们将其重命名为x1:xs1 NB!。所以我们继续看evens的定义。等等不要犹豫,多问一些好的,我想我明白了,我的想法对吗。。。5个晚上2:1:交换3:4:first\u four=5个晚上2:evens交换3:4:first\u four原来你一直都是对的甚至需要3个元素,但exchange只知道如何成对生成它们。
exchange:
pull(X) ... on_fail: ERROR
pull(Y) ... on_fail: ERROR
peek ... on_fail: push(Y); push(X); STOP
push(Y); push(X)
LOOP