CTM: Exercise 3-11

[ Posted by Urban Hafner Sat, 17 Sep 2005 14:37:12 GMT ]

The problem

Limitations of difference lists. What goes wrong when trying to append the same difference list more than once?

My solution

Assume you have the two difference lists (a|b|c|X)#X and (d|e|f|Y)#Y. To append them you bind X to (d|e|f|Y). Using the Append function from 3.4.4 what you get is (a|b|c|d|e|f|Y)#Y. But this changes the first difference list into (a|b|c|d|e|f|Y)#(d|e|f|Y).

If you then try to use the first difference list in another append with, say (x|y|Z)#Z you will get a unification error because what you try to do in the Append function is unify (d|e|f|Y) with (x|y|Z). This will of course fail. But in the first append of the difference list the unification was X=(d|e|f|Y) which of course succeeds always as X is an unbound variable.

Tags , , , , , ,

CTM: Exercise 3-10

[ Posted by Urban Hafner Thu, 15 Sep 2005 18:55:59 GMT ]

The problem

Checking if something is a list. Section 3.4.3 defines a function LengthL that calculates the number of elements in a nested list. To see whether X is a list or not, LengthL uses the function Leaf defined this way:

fun {Leaf X} case X of _|_ then false else true end end

What happens if we replace this by the following definition?:

fun {Leaf X} X\=(_|_) end

What goes wrong if we use this version of Leaf?

My solution

What happens is that when you call the second definition of Leaf with a non-nil value the computation suspends. I’m also not entirely sure on this one. But what probably happens is this. The two _ create two new unbound variables in the store. This then means that the disentailment check can’t decide and blocks.

Tags , , , , ,

CTM: Exercise 3-9

[ Posted by Urban Hafner Thu, 15 Sep 2005 18:55:46 GMT ]

The problem

Iterative computations and dataflow variables. The previous exercise shows that using dataflow variables sometimes makes it simpler to write iterative list operations. This leads to the following question. For any iterative operation defined with dataflow variables, is it possible to give another iterative definition of the same operation that does not use dataflow variables?

My solution

I’m really unsure about this one. If anyone can explain it in a nice and convincing way I’d happily replace my hand waving with it.

If we assume that iterative computation means the function Iterate from section 3.2.4 then it seems possible to replace any use of dataflow variables. Just translate your function into one similar to Iterate and you have removed any dataflow variables.

Tags , , , , , ,

CTM: Exercise 3-8

[ Posted by Urban Hafner Thu, 15 Sep 2005 18:55:23 GMT ]

The problem

An iterative append. This exercise explores the expressive power of dataflow variables. In the declarative model, the following definition if append is iterative:

fun {Append Xs Ys}
   case Xs
   of nil then Ys
   [] X|Xr then X|{Append Xr Ys}
   end
end

We can see this by looking at the expansion:

proc {Append Xs Ys ?Zs}
   case Xs
   of nil then Zs=Ys
   [] X|Xr then Zr in
      Zs=X|Zr
      {Append Xr Ys Zr}
   end
end

This can do a last call optimization because the unbound variable Zr ca be put in the list Zs and bound later. Now let us restrict the computation model to calculate with values only. How can we write an iterative append? One approach is to define two functions: (1) an iterative list reversal and (2) an iterative function that appends the reverse of a list to another list. Write an iterative append using this approach.

My solution

The iterative list reversal is already defined in the book in section 3.4.2.4. Taking this Append can be defined as follows:

local
   fun {IterAppend RevXs Ys}
      case RevXs
      of nil then Ys
      [] X|Xr then {IterAppend Xr X|Ys}
      end
   end
in
   fun {Append Xs Ys}
      {IterAppend {Reverse Xs} Ys}
   end
end

Tags , , , , ,

CTM: Exercise 3-7

[ Posted by Urban Hafner Wed, 14 Sep 2005 19:26:04 GMT ]

The problem

Another append function. Section 3.4.2 defines the Append function by doing recursion on the first argument. What happens if we try to do recursion on the second argument? Here is a possible solution:

fun {Append Ls Ms}
   case Ms
   of nil then Ls
   [] X|Mr then {Append {Append Ls [X]} Mr}
   end
end

Is this program correct? Does it terminate? Why or why not?

My solution

On first sight this definition seems to be correct. But of course it isn’t. This is an exercise from a CS textbook, so when a question like “Is this correct?” is asked is clear that the answer has to be “No!” :)

Anyway, here’s why this definition of Append is wrong: The problem is the inner call to Append. In this call Ms is bound to [X] which is the same as X|nil. But this means that it will always go into the second branch of the case statement. It will take apart the list and create the very same list for the inner call to Append again! So the inner Append actually never returns!

Apart from that the two lists can’t be appended together as nowhere in this Append function two lists are actually appended together using the | operator. So it’s doubly wrong.

Tags , , , , ,

CTM: Exercise 3-6

[ Posted by Urban Hafner Wed, 14 Sep 2005 19:25:26 GMT ]

The problem

State invariants. Write down a state invariant for the IterReverse function.

My solution

Define the state invariant P as follows:

P((Rs,Ys)) = (reverse(Xs) = reverse(Ys)|Rs)

  • The proof for P_(_S0~) follows from S0~ = (nil,Xs).
  • Assuming P_(_Si~) and S_i~ is not the final state, prove _P(S_i+1). This follows from the semantics of the case statement and the function call. Write _Si~ = (Rs,Ys). We are not in the final state, so Ys is of nonzero length. From the semantics, Y|Rs adds one element to Rs and the case statement removes this element from Ys. Therefore P_(_Si+1~) holds.

As you might have noticed I’ve used the proof for IterLength and just changed the bits concerning the state invariant. This is OK because the two functions are nearly the same.

Tags , , , , , ,

CTM: Exercise 3-5

[ Posted by Urban Hafner Wed, 14 Sep 2005 19:24:24 GMT ]

The problem

An iterative SumList. Rewrite the function SumList of section 3.4.2 to be iterative using the techniques developed for Length.

My solution

local
   fun {IterSumList S Es}
      case Es
      of nil then S
      [] E|Er then {IterSumList S+E Er}
      end
   end
in
   fun {SumList L}
      {IterSumList 0 L}
   end
end

Tags , , , , , ,

CTM: Exercise 3-4

[ Posted by Urban Hafner Sun, 11 Sep 2005 17:34:59 GMT ]

The problem

Iterative factorial. This chapter gives a definition of factorial whose maximum stack depth is proportional to the input argument. Give another definition of factorial which results in an iterative computation. Use the techniques of state transformations from an initial state, as shown in the IterLength example.

My solution


  fun {IterFact N}
     fun {IterFact2 N S}
        if N==0 then S
        elseif N>0 then {IterFact2 N-1 S*N}
        else raise domainError(N) end
        end
     end
  in
     {IterFact2 N 1}
  end

Tags , , , ,

CTM: Exercise 3-3

[ Posted by Urban Hafner Sun, 11 Sep 2005 17:34:45 GMT ]

The problem

The half-interval method. The half-interval method is a simple but powerful technique for finding roots of the equation f(x) = 0, where f_ is a continuous real function. The idea is that, if we are given real numbers _a and b_ such that f(a) < 0 < f(b), then _f must have a least one root between a_ and _b. To locate a root, let x = (a + b)/2 and compute f(x). If f(x) > 0, then f_ must have a root between _a and x_. If f(x) < 0 then _f must have a root between x_ and _b. Repeating this process will define smaller and smaller intervals that converge on a root. Write a declarative program to solve this problem using the techniques of iterative computation.

My solution


  local
     fun {GoodEnough A B} {Abs A-B} < 0.00001 end
  in
     fun {HalfInterval A B F}
        Mean=(A+B)/2.0 in
        if {GoodEnough A B} then
         Mean
        elseif {F Mean} > 0.0 then
         {HalfInterval A Mean F}
        else
         {HalfInterval Mean B F}
        end
     end
  end

Tags , , , ,

CTM: Exercise 3-2

[ Posted by Urban Hafner Fri, 02 Sep 2005 13:26:27 GMT ]

The problem

Cube roots. This chapter uses Newton’s method to calculate square roots. The method can be extended to calculate roots of any degree. For example, the following method calculates cube roots. Given a guess g_ for the cube root of _x, an improved guess is given by (x/g2 + 2g)/3. Write a declarative program to calculate cube roots using Newton’s method.

My solution

Taking the solution from Table 3.8 on page 123 the only thing that has to change is the Improve function. It has to be defined like this:


  fun {Improve Guess}
    (X/(Guess*Guess) + 2.0*Guess)/3.0
  end

Tags , , , ,

Older posts: 1 ... 3 4 5 6 7 ... 9