Haskell懒惰的评估和重写

时间:2015-01-21 18:10:53

标签: haskell

功能定义:

first_threes :: [Int]                     -- first three numbers repeated
first_threes = 1:2:3:first_threes         -- th.1

take :: Int -> [a] -> [a]                 -- take
take 0 _ = []                             -- t.1
take n (x:xs) = x : (take (n - 1) xs)     -- t.2

sum :: [Int] -> Int                       -- summation of an Int list
sum [] = 0                                -- s.1
sum (x:xs) = x + (sum xs)                 -- s.2

我需要使用上面函数的定义来重写下面的语句。我需要得到答案9.我需要使用“懒惰评估”证明每个解决方案的合理性。

Hugs_Main> my sum (my take 5 first_threes)
9

我正在努力找出20个解决方案,获得9个答案。以下是我的前10个解决方案,但我想不出别的。任何人都可以帮忙吗?

我的前10个解决方案:

my_sum (my_take 5 first_threes)
my_sum (my_take 5 (1:2:3:first_threes))
my_sum (my_take 5 (1:2:first_threes))
my_sum (my_take 5 (2:first_threes))
my_sum (my_take 4 (3:first_threes))
my_sum (1:2:3:(my_take 2 (first_threes)))
my_sum (1:2:(my_take 3 (first_threes)))
my_sum (1:(2:my_take 3 (3:first_threes)))
my_sum (1:(my_take 4 (2:3:first_threes)))
my_sum (1:(my_take 4 (2:first_threes)))

2 个答案:

答案 0 :(得分:1)

我认为这开始了老师想要看到的内容

my_sum (my_take 5 first_threes)
-- th.1
my_sum (my_take 5 (1:2:3:first_threes))
-- t.2
my_sum (1 : my_take 4 (2:3:first_threes))
-- s.2
1 + my_sum (my_take 4 (2:3:first_threes))
-- continue yourself

关于术语的说法:检查是否必须使用解决方案。我给了你一些重写。在每一步中,您都使用其中一个等于重写您的术语。评论指出我用于重写的内容..

答案 1 :(得分:0)

-- original expression
sum (take 5 first_threes)

-- (substitution) apply `take 5 first_threes` to `sum` 
case take 5 first_threes of
  [] -> 0
  (x : xs) -> x + sum xs

-- pattern matching force evaluation of the first cons constructor so
-- we need eval `take 5 first_threes` first

-- apply `first_threes` to `take n` (substitution)
(\ n -> case n of
  0 -> [] 
  _ -> case first_trees of 
         _ -> []
         (x : xs) -> x : take (n - 1) xs) 5

-- apply 5 to the lambda (substitution)
case 5 of
  0 -> [] 
  _ -> case first_trees of 
         _ -> []
         (x : xs) -> x : take (5 - 1) xs

-- 5 is already in normal form, after case analysis we will have
case first_trees of 
  _ -> []
  (x : xs) -> x : take (5 - 1) xs

-- pattern matching again (see above)
case 1 : 2 : 3 : first_threes of
  _ -> []
  (x : xs) -> x : take (5 - 1) xs

-- after case analysis (?) we will have
1 : take (5 - 1) (2 : 3 : first_threes)

-- now we return back to our original expression
case 1 : take (5 - 1) (2 : 3 : first_threes) of
  [] -> 0
  (x : xs) -> x + sum xs

-- after case analysis we will have
1 + sum (take (5 - 1) (2 : 3 : first_threes))

-- (+) operator is strict in both args 
-- the first arg is already evaluated, but we also need to evaluate the second
1 + case take (5 - 1) (2 : 3 : first_threes) of
      [] -> 0
      (x : xs) -> x + sum xs

-- and so on...

-- in the end we will get
1 + (2 + (3 + (1 + (2 + (0)))))
-- which is evaluated in reverse order (starting from the `0`)