Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Learn how to write your own transducers. A complement from my blog post serie "Build Your Own Transducer and Impress Your Cat".

License

NotificationsYou must be signed in to change notification settings

green-coder/transducer-exercises

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Contains exercises on implementing custom transducers in Clojure.

It is recommended (but not required) to read firstthis serie of articles first.

The solutions are linked at the end of each section.

Fair notice

Implementing transducers is hard and you may feel confused.

Cry Kid Meme

That's normal and to be expected, it happens also to me when I read my own code. Just don't give up.

No Operation transducer

Implement a transducer that does nothing but passing the data from his input to his output. Functionally speaking, it is an identity transducer.

(into [] identity (range3)); => [0 1 2]

Link to the solution

Use it as your transducer template for the following.

Prepare for battle

  • Implement the(debug in out) transducer that helps to debug.
; We use this function instead of `into` for debugging.; The reason is that this avoids using transient; structures which do not `print` nicely.(defnslow-into [to xf from]  (transduce xf conj to from))(slow-into [] (debug"in""out") (range3));; Outputs:; in 0; out [0]; in 1; out [0 1]; in 2; out [0 1 2]
  • Add the(debug),(debug indent) and(debug indent in out) variants for convenience. They are all calling the(debug in out) transducer under the hood.
(slow-into []           (comp (debug)                 (debug2)                 (debug4">""<"))                 (debug"      >""      <")); 6-spaces prefix           (range3));; Outputs:; > 0;   > 0;     > 0;       > 0;       < [0];     < [0];   < [0]; < [0]; > 1;   > 1;     > 1;       > 1;       < [0 1];     < [0 1];   < [0 1]; < [0 1]; > 2;   > 2;     > 2;       > 2;       < [0 1 2];     < [0 1 2];   < [0 1 2]; < [0 1 2]

Link to a solution

Strange patterns, it reminds me of ...

The PHP Hadouken !!!

PHP Hadouken

We are now ready to face real transducer implementations and confront an army of problems.

May I beg your pardon?

You heard me well, I want you to implement the following transducer.

(defbeg-data (list:may:i:beg:your:pardon:?))(into [] (beg2) beg-data); => [:may :may :i :i :beg :beg :your :your :pardon :pardon :? :?]

Link to a partial solution

Make sure that you are handling the early termination as well.

(into []      (comp (take3)            (beg2))      beg-data); => [:may :may :i :i :beg :beg]

Test for both sides.

(into []      (comp (beg2)            (take3))      beg-data); => [:may :may :i]

Test with the debug transducer (expect problems and losing some hair).

(slow-into []           (comp (debug0)                 (beg2)                 (debug2)                 (take3)                 (debug4))           beg-data); Output:; > :may;   > :may;     > :may;     < [:may];   < [:may];   > :may;     > :may;     < [:may :may];   < [:may :may]; < [:may :may]; > :i;   > :i;     > :i;     < [:may :may :i];   < #reduced[{:status :ready, :val [:may :may :i]} 0x8cdcdd1]; < #reduced[{:status :ready, :val [:may :may :i]} 0x8cdcdd1]; Result:; => [:may :may :i]

Thebeg transducer should not continue sending data downstream after it receives a reduced result. Fix your implementation if needed.

Link to a complete solution

All your data are belong to me

Catducer

Implement themy-cat transducer. For each step, you will need to adapt your implementation to the new requirements described by the test samples.

  • Step 1, shapeless cat

It functions similarly toclojure.core/cat. Don't handle early termination at the moment.

(defcat-data [[12:fish3] [:heat4] [5:sleep6] [7]])(into [] my-cat cat-data); => [1 2 :fish 3 :heat 4 5 :sleep 6 7]

Link to a solution, part 1

  • Step 2, hungry cat

As you can see, the transducer is keeping for itself all the fishes and the heat.

(into [] my-cat cat-data); => [1 2 3 4 5 :sleep 6 7]

Link to a solution, part 2

  • Step 3, sleepy cat

That version of the transducer falls asleep an the:sleep keyword and do not process any subsequent data.

(into [] my-cat cat-data); => [1 2 3 4 5]

Link to a solution, part 3

  • Step 4, correct cat

At last, we want our transducer to respect the normal early termination (withreduced? tested on the downstream result) in a correct manner.

(into [] (comp (take2)               my-cat)      cat-data); => [1 2 3 4](into [] (comp my-cat               (take2))      cat-data); => [1 2](slow-into [] (comp (debug0)                    my-cat; try replacing it with `cat` and compare                    (debug2)                    (take2)                    (debug4))           cat-data);; Outputs:; > [1 2 :fish 3];   > 1;     > 1;     < [1];   < [1];   > 2;     > 2;     < [1 2];   < #reduced[{:status :ready, :val [1 2]} 0x517a7e8e]; < #reduced[{:status :ready, :val [1 2]} 0x517a7e8e]

Link to a complete solution

  • Provide an idiomatic equivalent tomy-cat.

Link to the idiomatic solution

A.D.D. transducer

  • Implement a transducer that daydream during a number of elements. While in the daydream state, it buffers its input. When it stops daydreaming, it processes all of its buffer as a batch, then daydreams again.

Thea-d-d transducer never loses data.

(into [] (a-d-d3) (range10)); => [0 1 2 3 4 5 6 7 8 9]; Try:(slow-into [] (comp (debug0)                    (a-d-d3)                    (debug2))           (range10))

Link to a partial solution

  • Verify that it works well with early termination.
(slow-into [] (comp (debug0)                    (a-d-d3)                    (debug2)                    (take5))           (range10)); => [0 1 2 3 4]

Link to a complete solution

  • Changea-d-d so that it works similarly toclojure.core/partition-all.
(into [] (a-d-d3) (range10)); => [[0 1 2] [3 4 5] [6 7 8] [9]]

Link to a partition-all '-ish' solution

  • Verify that it works well with early termination.
(slow-into [] (comp (debug0)                    (a-d-d3)                    (debug2)                    (take2))           (range10)); => [[0 1 2] [3 4 5]]

A reducer inside a transducer

Implementserieduce which provides a transducer which reduces incoming elements and emits all intermediary elements.

(into [] (serieduce conj [12]) (range36)); => [[1 2 3] [1 2 3 4] [1 2 3 4 5]](into [] (serieduce +) (range5)); => [0 1 3 6 10]

Link to a partial solution

Link to a complete solution

Congratulations if you made it that far!

Success Kid

You are one of a few.

About

Learn how to write your own transducers. A complement from my blog post serie "Build Your Own Transducer and Impress Your Cat".

Topics

Resources

License

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp