Haskell - 程序的结果

时间:2014-07-21 17:38:21

标签: haskell trace

我刚开始学习Haskell,在考试期间,我被要求回答如果被调用会返回什么成本函数,但我无法理解会发生哪些步骤。我再次参加考试,但我无法理解我应该如何解决这类课程。

任何帮助将不胜感激!

cost = n(twice, inc, 3)
n(h,s,x) = if (x<1) then (h s x) else n(h, (h s), x-1)
inc x = x+1
twice n a = n (n a)

1 个答案:

答案 0 :(得分:6)

类型签名在这里确实会有很长的路要走。让我们从最简单的inc

开始
inc :: Num a => a -> a
inc x = x + 1

这很容易派生,因为+ 1的类型为Num a => a -> a,您可以使用:type (+1)在GHCi中进行检查。接下来,让我们看一下函数twice。很明显,传入的n必须是一个函数,因为它适用于an a。因为它适用于n aa,所以这两个表达式必须具有相同的类型,并且n必须只有一个参数,所以我们可以说twice具有型

twice :: (a -> a) -> a -> a
twice n a = n (n a)

现在我们可以找出n。它需要一个元组(h, s, x)作为参数,并以递归方式调用。 h必须是两个参数的函数,因为它适用于sx,而s在没有更多上下文的情况下是未知的。 x由于与Num a => aOrd a => a一起使用,因此必须同时为< 1-1,因此我们可以将签名写为

n :: (Num a, Ord a) => (b -> a -> c, b, a) -> c
n (h, s, x) = if x < 1 then h s x else n (h, h s, x - 1)

请注意,我在这里删除了一些不必要的parens。最后,我们可以找出cost的类型,它只是n的返回类型:

cost :: (Num a, Ord a) => a
cost = n (twice, inc, 3)

但这会带来什么回报呢?对于初学者来说,它会重写n的定义,但twiceinc3替换为:

if 3 < 1
    then twice inc 3
    else n (twice, twice inc, 3 - 1)

显然3 < 1是假的,所以让我们减少n (twice, twice inc, 3 - 1)

if 2 < 1
    then twice (twice inc) 2
    else n (twice, twice (twice inc), 2 - 1)

同样的故事,2 < 1是假的,所以让我们继续减少:

if 1 < 1
    then twice (twice (twice inc)) 1
    else n (twice, twice (twice (twice inc)), 1 - 1)

这一步没有什么新内容,再试一次:

if 0 < 1
    then twice (twice (twice (twice inc))) 0
    else n (twice, twice (twice (twice (twice inc))), 0 - 1)

此处我们有0 < 1,因此我们选择twice (twice (twice (twice inc))) 2的分支。要解决此问题,只需将inc0插入twice的定义中:

twice (twice (twice (twice inc))) 0
           = twice (twice (twice (inc . inc))) 0
           = twice (twice (inc . inc . inc . inc)) 0
           = twice (inc . inc . inc . inc . inc . inc . inc . inc) 0
           = (inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc) 0
           = 16

我们现在不能再减少这个表达了!所以整个减排链都是

cost = n (twice, inc, 3)
     = if 3 < 1
           then twice inc 3
           else n (twice, twice inc, 3 - 1)
     = n (twice, twice inc, 2)
     = if 2 < 1
           then twice (twice inc) 2
           else n (twice, twice (twice inc), 2 - 1)
     = n (twice, twice (twice inc), 1)
     = if 1 < 1
           then twice (twice (twice inc)) 1
           else n (twice, twice (twice (twice inc)), 1 - 1)
     = n (twice, twice (twice (twice inc)), 0)
     = if 0 < 1
           then twice (twice (twice (twice inc))) 0
           else n (twice, twice (twice (twice (twice inc))), 0 - 1)
     = twice (twice (twice (twice inc))) 0
     = inc (inc 0)
     = inc (0 + 1)
     = (inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc.inc) 0
     = 16

(为了保持可读性,我使用twice f = f . f代替twice f x = f (f x),但这些定义是等效的)