简体   繁体   中英

Haskell foldr reduction

I am still very new to Haskell and I am trying to solve a problem. I have attempted something but I am very sure it is wrong.

The Problem:

foldr : f x NIL = x
foldr : f x (cons a list) = f a (foldr f x list)

Let's have some fun and combine the features of a number of different languages.

(1) Borrowing from the course notes and Haskell, let's define a function foldl,

(a) foldl fx NIL = x

(b) foldl fx (cons a list) = foldl f (fxa) list

(2) Borrowing from Python, we can treat a string as a sequence (ie a list) of characters,

“bar” ≡ (‘b’ ‘a’ ‘r’) ≡ [‘b’, ‘a’, ‘r’]

(3) Borrowing from Lisp, we can use cons cells to represent or create lists,

(‘b’ ‘a’ ‘r’) ≡ (cons ‘b’ (cons ‘a’ (cons ‘r’ nil)))

(4) Borrowing from Fortran, we can define a string concatenation function, //,

‘concate’//’nation’ ⇒‘concatenation’

(5) Borrowing from Scheme, define a toggle function,

f x y = f y x,
(define toggle (lambda (f x y)  (f y x)))

That is, the toggle function switches its arguments, in Lambda Calculus, it's,

|_f. |_x. |_y. f y x

Thus, for example,

(f ‘back’ ‘drop’) ⇒(f ‘drop’ back’)

In this question, please trace the execution/reduction of the following function:

foldl (toggle //) nil (“foo” “bar” “baz”)

Below is a Hint I am Given:

    foldl (toggle //) nil (“foo” “bar” “baz”)

Step1: Start with (1b), left side, foldl fx (cons a list)

        with f = (toggle //), x = nil, and list = (“foo” “bar” “baz”)

Step2: Use (3) to recursively expand the list

Step3: Use (1b), right-side, foldl f (fxa) list

        to recursively apply f, (toggle //), to the expanded list

Step4: Use (5) to apply the toggle functions in the list expression.

Step5: Use (4), //, to reduce the expression

What I Got:

foldl (toggle //) nil (“foo” “bar” “baz”)
foldl f x (cons a list) – via (1b)
foldl f x(a list)  – via (3)
foldl f (f x a) list – via (1b)
foldl (toggle //) (toggle // x a) list – via(5)
foldl x // // a list – via (4)
foldl nil a (“foo” “bar” “baz”)

I know that can't be right but I feel like I am somewhere near. If I could get some guidance I feel I could become unstuck and have a successful understanding.

start with

foldl (toggle //) nil (“foo” “bar” “baz”)
{ 1b }
= foldl (toggle //) ((toggle //) nil "foo") (“bar” “baz”)

...

remarks/questions:

  • ("foo" "bar" "baz") is not Haskell for lists! (what are the strange " ?)
  • (toggle //) is not Haskell syntax for operators either (it's (toggle (//)) )
  • what strategy are you supposed to use? Depending on it you have to continue with the (toggle //) nil "foo") or the foldl

the toggle would be

(toggle //) nil "foo"
{ 5 }
= (//) "foo" nil
{ 4 }
"foo"

the other would be the same again:

foldl (toggle //) ((toggle //) nil "foo") (“bar” “baz”)
{ 1b }
= foldl (toggle //) ((toggle //) ((toggle //) nil "foo") "bar") ("baz")

I'm sure you can work out the rest (it's really just putting the right thing into the right spot )

The first thing I would do is replace all the alien syntax and names with Haskell syntax and names.

toggle              ⇒ flip
nil                 ⇒ []
(“foo” “bar” “baz”) ⇒ ["foo", "bar", "baz"]
(//)                ⇒ (++)

Giving:

foldl (toggle (//)) nil (“foo” “bar” “baz”)
⇒ foldl (flip (++)) [] ["foo", "bar", "baz"]

Note: I am correcting (toggle //) to (toggle (//)) because I think the latter is what was intended. The former is a type error.

Now you just expand the definition of foldl . Again I would replace the alien syntax and names with Haskell syntax and names.

foldl f x NIL = x
foldl f x (cons a list) = foldl f (f x a) list

Becomes:

foldl f a [] = a
foldl f a (x:xs) = foldl f (f a x) xs

Now you apply foldl to its arguments. There are are a couple things you can do. One thing is to rewrite foldl so it is an expression.

foldl =
  \f -> \a -> \xxs ->
    case xxs of
      []   -> a
      x:xs -> foldl f (f a x) xs

Or on one line as:

foldl = \f -> \a -> \xxs -> case xxs of [] -> a; x:xs -> foldl f (f a x) xs

You can also desugar the list ["foo", "bar", "baz"] to "foo":"bar":"baz":[] , which makes pattern matching more obvious.

Now expand foldl and apply:

foldl (flip (++)) [] ("foo":"bar":"baz":[])
⇒ (\f -> \a -> \xxs -> case xxs of [] -> a; x:xs -> foldl f (f a x) xs) (flip (++)) [] ("foo":"bar":"baz":[])
⇒ (\a -> \xxs -> case xxs of [] -> a; x:xs -> foldl (flip (++)) ((flip (++)) a x) xs) [] ("foo":"bar":"baz":[])
⇒ (\xxs -> case xxs of [] -> []; x:xs -> foldl (flip (++)) ((flip (++)) [] x) xs) ("foo":"bar":"baz":[])
⇒ case "foo":"bar":"baz":[] of [] -> []; x:xs -> foldl (flip (++)) ((flip (++)) [] x) xs

Simplify the case expression:

case ("foo":"bar":"baz":[]) of [] -> []; x:xs -> foldl (flip (++)) ((flip (++)) [] x) xs
⇒ foldl (flip (++)) ((flip (++)) [] "foo") ("bar":"baz":[])

You can finish the normalisation in the same manner.

Once you understand that a function definition such as foldl is really just sugar on a case expression you can take a shortcut.

Note: There are other rich syntaxes such as guards and do-notation. When you want to evaluate them it will help to know the underlying expression.

Starting from:

foldl (flip (++)) [] ("foo":"bar":"baz":[])

We can look at this definition of foldl :

foldl f a [] = a
foldl f a (x:xs) = foldl f (f a x) xs

And immediately choose either the a definition or the foldl f (fax) xs definition based which case matches. In this case it is the latter. Having chosen the correct definition we substitute all the parameters for arguments and quickly arrive at the same expression as before:

foldl (flip (++)) ((flip (++)) [] "foo") ("bar":"baz":[])

You can see that my general approach has been to simplify the syntax. That is, simpler to manipulate rather than simpler to read or write, which usually means reducing to fewer primitives. We managed with just using case , abstraction (ie \\x -> m ), and application (ie fx , substituting parameters for arguments). This is a good approach if the rules of how to use the richer syntax (or in the case of this problem, invented syntax) are not clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM