├── .gitignore ├── FUNDING.yml ├── LICENSE ├── README.md ├── clojure ├── README.md ├── basics │ ├── boolean.clj │ ├── control-flow.clj │ ├── define-functions.clj │ ├── destructuring.clj │ ├── keywords.clj │ ├── let.clj │ ├── namespaces.clj │ ├── naming-values.clj │ └── recursion.clj ├── clojure_applied │ └── model_your_domain │ │ ├── 1.modeling-entities.clj │ │ ├── 2.constructing-entities.clj │ │ └── 3.apollo.clj ├── data_structures │ ├── atom.clj │ ├── data-structures.clj │ ├── hash-map.clj │ ├── laziness.clj │ ├── lists.clj │ ├── persistent-data-structures.clj │ ├── sets.clj │ └── vectors.clj ├── functional │ └── composition.clj └── functions │ ├── anonymous-functions.clj │ ├── comparators.clj │ ├── core-functions.clj │ ├── filter.clj │ ├── function-body.clj │ ├── functional.clj │ ├── functions.clj │ ├── high-order-functions.clj │ ├── polymorphism.clj │ ├── reduce.clj │ └── returning-functions.clj ├── elixir ├── README.md └── learn-fp-with-elixir │ ├── 01.thinking-functional │ ├── 01.immutable_data.ex │ └── 02.functions.ex │ ├── 02.variables-and-functions │ ├── 01.values.ex │ └── exercises │ │ ├── 01.ex │ │ ├── 02.ex │ │ ├── 03.ex │ │ └── 04.ex │ └── 03.using-pattern-matching-to-control-the-program-flow │ ├── 01.equal_operator.ex │ └── 02.destructuring.ex ├── haskell ├── README.md ├── basics.hs └── function_application.hs ├── javascript ├── README.md ├── books │ ├── composing_software │ │ ├── README.md │ │ ├── composing_functions.js │ │ ├── declarative_programming.js │ │ ├── functors.js │ │ └── intro_to_js.js │ └── mostly_adequate_guide_to_functional_programming │ │ ├── README.md │ │ ├── ch02.js │ │ ├── ch03.js │ │ └── ch04.js ├── closure.js ├── currying.js ├── first_class_citizens.js ├── function_as_value.js ├── function_composition.js ├── high_order_functions.js ├── immutability │ ├── avoid_array_mutability.js │ ├── immutability.js │ └── slugify.js ├── lazy.js ├── partial_application.js ├── purity_part_1.js ├── purity_part_2.js ├── reduce.js └── referentially_transparent_function.js ├── programming_challenges ├── 4clojure │ ├── problem01.clj │ ├── problem02.clj │ ├── problem03.clj │ ├── problem04.clj │ ├── problem05.clj │ ├── problem06.clj │ ├── problem07.clj │ ├── problem19.clj │ └── problem20.clj ├── README.md ├── exercism │ ├── clojure │ │ ├── armstrong-numbers │ │ │ ├── .lein-failures │ │ │ ├── .lein-repl-history │ │ │ ├── README.md │ │ │ ├── project.clj │ │ │ ├── src │ │ │ │ └── armstrong_numbers.clj │ │ │ ├── target │ │ │ │ ├── classes │ │ │ │ │ └── META-INF │ │ │ │ │ │ └── maven │ │ │ │ │ │ └── armstrong-numbers │ │ │ │ │ │ └── armstrong-numbers │ │ │ │ │ │ └── pom.properties │ │ │ │ └── stale │ │ │ │ │ └── leiningen.core.classpath.extract-native-dependencies │ │ │ └── test │ │ │ │ └── armstrong_numbers_test.clj │ │ ├── hello-world │ │ │ ├── README.md │ │ │ ├── project.clj │ │ │ ├── src │ │ │ │ └── hello-world.clj │ │ │ └── test │ │ │ │ └── hello-world-test.clj │ │ └── two-fer │ │ │ ├── .lein-failures │ │ │ ├── .nrepl-port │ │ │ ├── README.md │ │ │ ├── project.clj │ │ │ ├── src │ │ │ └── two_fer.clj │ │ │ ├── target │ │ │ ├── classes │ │ │ │ └── META-INF │ │ │ │ │ └── maven │ │ │ │ │ └── two-fer │ │ │ │ │ └── two-fer │ │ │ │ │ └── pom.properties │ │ │ ├── repl-port │ │ │ └── stale │ │ │ │ └── leiningen.core.classpath.extract-native-dependencies │ │ │ └── test │ │ │ └── two_fer_test.clj │ └── javascript │ │ ├── collatz-conjecture.js │ │ ├── gigasecond.js │ │ ├── hello-world.js │ │ ├── leap.js │ │ ├── resistor-color.js │ │ ├── resistor-colors.js │ │ ├── reverse-string.js │ │ ├── triangle.js │ │ └── two-fer.js ├── hacker_rank │ ├── array_of_n_elements │ │ ├── array_of_n_elements.clj │ │ └── array_of_n_elements_without_range.clj │ ├── basics │ │ ├── hello_world.clj │ │ ├── hello_world_n_times.clj │ │ └── solve_me_first.clj │ ├── eval_ex │ │ └── main.clj │ ├── fibonacci │ │ └── fibonacci.js │ ├── filter_array │ │ └── filter_array.clj │ ├── filter_positions_in_a_list │ │ └── filter_positions_in_a_list.clj │ ├── list_length │ │ ├── list_length.clj │ │ └── list_length_reduce.clj │ ├── list_replication │ │ └── list_replication.clj │ ├── reverse_a_list │ │ ├── reverse_a_list.clj │ │ ├── reverse_a_list_into.clj │ │ └── reverse_a_list_reduce.clj │ ├── sum_of_odd_elements │ │ └── sum_of_odd_elements.clj │ └── update_list │ │ ├── update_list.clj │ │ ├── update_list_anonymous.clj │ │ ├── update_list_map.clj │ │ └── update_list_map_anonymous.clj └── playground │ ├── collisions.clj │ └── jobs │ ├── job.clj │ └── resource │ ├── input.json │ └── output.json ├── python ├── README.md └── intro.py ├── ruby ├── README.md ├── immutable_array.rb └── immutable_select_with_reduce.rb └── rust └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode 3 | .exercism 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [imteekay] 2 | custom: [https://teekay.substack.com] 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) TK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Functional Programming Learning Path 4 | 5 | ## Table of Content 6 | 7 | - [Foundation](#foundation) 8 | - [Why Functional](#why-functional) 9 | - [Advanced Topics](#advanced-topics) 10 | - [Talks](#talks) 11 | - [Books](#books) 12 | - [Declarative Programming](#declarative-programming) 13 | - [Blogs](#blogs) 14 | - [Projects](#projects) 15 | - [Podcasts](#podcasts) 16 | - [Courses](#courses) 17 | - [Lists](#lists) 18 | - [Community](#community) 19 | - [JavaScript](https://github.com/imteekay/functional-programming-learning-path/tree/master/javascript) 20 | - [Rust](https://github.com/imteekay/functional-programming-learning-path/tree/master/rust) 21 | - [Clojure](https://github.com/imteekay/functional-programming-learning-path/tree/master/clojure) 22 | - [Python](https://github.com/imteekay/functional-programming-learning-path/tree/master/python) 23 | - [Ruby](https://github.com/imteekay/functional-programming-learning-path/tree/master/ruby) 24 | - [Programming Challenges](https://github.com/imteekay/functional-programming-learning-path/tree/master/programming_challenges) 25 | 26 | ## Foundation 27 | 28 | - [Functional Programming Learning Path](https://purelyfunctional.tv/learning-paths/functional-programming/) 29 | - [Introduction to Funcional Programming - edX](https://www.edx.org/course/introduction-functional-programming-delftx-fp101x-0) 30 | - [Como programar funcional?](https://www.youtube.com/watch?v=jIYfTKYXJr8) 31 | - [Demystifying functional programming](https://medium.com/building-nubank/demystifying-functional-programming-in-a-real-company-e954a2591504) 32 | - [Programação Funcional para iniciantes](https://medium.com/trainingcenter/programa%C3%A7%C3%A3o-funcional-para-iniciantes-9e2beddb5b43) 33 | - [Awesome Functional Programming](https://github.com/xgrommx/awesome-functional-programming) 34 | - [Functional Programming Jargon](https://github.com/hemanth/functional-programming-jargon) 35 | - [Your functional journey](https://purelyfunctional.tv/guide/your-functional-journey/) 36 | - [The Benefits of Pure Functions](https://alvinalexander.com/scala/fp-book/benefits-of-pure-functions) 37 | - [Pure Functions](https://www.sitepoint.com/functional-programming-pure-functions/) 38 | - [Functional Koans](https://github.com/relevance/functional-koans) 39 | - [Programação funcional, imutabilidade, e previsibilidade](https://mauricioszabo.wordpress.com/2016/03/22/programacao-funcional-imutabilidade-e-previsibilidade/) 40 | - [A practical introduction to functional programming](https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming) 41 | - [An introduction to functional programming](https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming) 42 | - [Software Composition](https://medium.com/javascript-scene/composing-software-an-introduction-27b72500d6ea) 43 | - [Functional Education](http://bitemyapp.com/posts/2014-12-31-functional-education.html) 44 | - [What is functional?](https://dev.to/drbearhands/functional-fundamentals-what-is-functional-l66) 45 | - [Types as propositions, programs as proofs](https://dev.to/drbearhands/functional-fundamentals-types-as-propositions-programs-as-proofs-56gh) 46 | - [So You Want to be a Functional Programmer (Part 1)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-1-1f15e387e536) 47 | - [So You Want to be a Functional Programmer (Part 2)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-2-7005682cec4a) 48 | - [So You Want to be a Functional Programmer (Part 3)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7) 49 | - [So You Want to be a Functional Programmer (Part 4)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-4-18fbe3ea9e49) 50 | - [So You Want to be a Functional Programmer (Part 5)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-5-c70adc9cf56a) 51 | - [So You Want to be a Functional Programmer (Part 6)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-6-db502830403) 52 | - [Friendly Functional Programming](https://functional.works-hub.com/learn/friendly-functional-programming-b3e93) 53 | - [Practical Functional Programming](https://hackernoon.com/practical-functional-programming-6d7932abc58b) 54 | - [Destroy All Ifs](http://degoes.net/articles/destroy-all-ifs) 55 | - [THE PILLARS OF FUNCTIONAL PROGRAMMING (PART 1)](https://sigma.software/about/media/pillars-functional-programming-part-1) 56 | - [Functional Programming Patterns: Cookbook](https://medium.com/@karthikiyengar/functional-programming-patterns-cookbook-3a0dfe2d7e0a) 57 | 58 | ## Higher Order Functions 59 | 60 | - [Getting a handle on Reduce](https://adambard.com/blog/getting-a-handle-on-reduce/) 61 | 62 | ## Immutability 63 | 64 | - [Immutability - something worth striving for](https://dev.to/rwoodnz/immutability---something-worth-striving-for-3ppp) 65 | - [Why shared mutable state is the root of all evil](http://henrikeichenhardt.blogspot.com/2013/06/why-shared-mutable-state-is-root-of-all.html) 66 | - [Immutable data](https://www.sitepoint.com/functional-programming-ruby-value-objects/) 67 | - [Thoughts on Immutability, CI/CD, FP](https://www.infoq.com/podcasts/Vitor-Olivier) 68 | 69 | ## Why Functional 70 | 71 | - [Why functional programming matters](https://hackernoon.com/why-functional-programming-matters-c647f56a7691) 72 | - [Why Functional Programming?](https://purelyfunctional.tv/article/why-functional-programming/) 73 | - [Advantages of Functional Programming](https://blog.codeship.com/advantages-of-functional-programming/) 74 | - [Pros and cons of functional programming](https://itnext.io/pros-and-cons-of-functional-programming-32cdf527e1c2) 75 | - [What are the benefits of functional programming?](https://stackoverflow.com/a/128128/3159162) 76 | - [Benefits of Functional Programming](https://alvinalexander.com/scala/fp-book/benefits-of-functional-programming) 77 | - [Benefits of Functional Programming beyond map/filter/reduce](https://www.youtube.com/watch?v=oaa4XiwEq1E&ab_channel=Jfokus) 78 | - [Benefits of Functional Programming by Example](https://medium.com/@nickmccurdy/benefits-of-functional-programming-by-example-76f1135b0b18) 79 | - [Goodbye, Object Oriented Programming](https://medium.com/@cscalfani/goodbye-object-oriented-programming-a59cda4c0e53) 80 | - [Switching from OOP to Functional Programming](https://medium.com/@olxc/switching-from-oop-to-functional-programming-4187698d4d3) 81 | 82 | ## Advanced Topics 83 | 84 | - [Transducers: Efficient Data Processing Pipelines in JavaScript](https://medium.com/javascript-scene/transducers-efficient-data-processing-pipelines-in-javascript-7985330fe73d) 85 | - [Functors, Monads and better functions](https://dev.to/drbearhands/functors-monads-and-better-functions-26f3) 86 | - [Why Curry Helps](https://hughfdjackson.com/javascript/why-curry-helps/) 87 | - [Curry and Function Composition](https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983) 88 | - [Functional JavaScript: Function Composition For Every Day Use](https://hackernoon.com/javascript-functional-composition-for-every-day-use-22421ef65a10) 89 | - [A Modern Architecture for FP](http://degoes.net/articles/modern-fp) 90 | - [Modern Functional Programming: Part 2](http://degoes.net/articles/modern-fp-part-1) 91 | - [Functional Programming, Abstraction, and Naming Things](http://www.stephendiehl.com/posts/abstraction.html) 92 | - [SOLID: the next step is Functional](http://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/) 93 | - [Functional Design Patterns](https://www.youtube.com/watch?reload=9&v=srQt1NAHYC0&ab_channel=NDCConferences) 94 | - [Free Monads Explained (pt 1)](https://medium.com/@olxc/free-monads-explained-pt-1-a5c45fbdac30) 95 | - [Perpetual Currying in JavaScript](https://medium.com/@paramsingh_66174/perpetual-currying-in-javascript-5ae1c749adc5) 96 | 97 | ## Advanced Topics: Category Theory 98 | 99 | - [From design patterns to category theory by Mark Seemann](http://blog.ploeh.dk/2017/10/04/from-design-patterns-to-category-theory/) 100 | 101 | ## Talks 102 | 103 | - [Functional programming design patterns by Scott Wlaschin](https://www.youtube.com/watch?v=E8I19uA-wGY&ab_channel=IvanPlyusnin) 104 | - [Why Functional Programming Matters by John Hughes](https://www.youtube.com/watch?v=XrNdvWqxBvA&ab_channel=ConfEngine) 105 | 106 | ## Books 107 | 108 | - [How to Design Programs](https://htdp.org/2019-02-24/) 109 | - [Category Theory for Programmers](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/) 110 | - [SICP - Structure and Interpretation 111 | of Computer Programs](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book.html) 112 | 113 | ## Declarative Programming 114 | 115 | - [What is declarative programming?](https://stackoverflow.com/a/129639/3159162) 116 | - [Declarative vs Imperative Programming by Ian Mundy](https://codeburst.io/declarative-vs-imperative-programming-a8a7c93d9ad2) 117 | - [Imperative vs Declarative Programming by Tyler McGinnis](https://tylermcginnis.com/imperative-vs-declarative-programming/) 118 | - [Imperative versus declarative code… what’s the difference?](https://medium.com/front-end-hacking/imperative-versus-declarative-code-whats-the-difference-adc7dd6c8380) 119 | 120 | ## Blogs 121 | 122 | - [Patterns in Functional Programming](https://patternsinfp.wordpress.com/) 123 | - [Kevin Sookocheff - Functional Programming](https://sookocheff.com/tags/functional-programming/) 124 | 125 | ## Projects 126 | 127 | - [YouTube instant search with FP](https://jaysoo.ca/2016/01/13/functional-programming-little-ideas/) 128 | 129 | ## Podcasts 130 | 131 | - [LambdaCast](https://soundcloud.com/lambda-cast) 132 | - [Programação Funcional com Erick Pintor e Bruno Tavares](http://tecnologicamentearretado.com.br/2014/12/31/programacao-funcional-com-erick-e-bruno/) 133 | - [Programação Funcional com Juliano alves](https://www.tecnoretorica.com.br/2013/04/programacao-funcional/) 134 | - [Programação Funcional - Inviavel Podcast](http://inviavelpodcast.com/10/) 135 | - [CapyCast #10 Linguagens Funcionais Com Marcelo Camargo e Derek Stavis](https://player.fm/series/capycast/capycast-10-linguagens-funcionais-com-marcelo-camargo-e-derek-stavis) 136 | - [The Imposter's Handbook: Functional Programming and Databases](https://www.orbit.fm/bookbytes/17) 137 | - [Functional Programming Languages and the Pursuit of Laziness with Dr. Simon Peyton Jones](https://player.fm/series/microsoft-research-podcast-1910051/ep-056-rerun-functional-programming-languages-and-the-pursuit-of-laziness-with-dr-simon-peyton-jones) 138 | 139 | ## Courses 140 | 141 | - [Functional Programming Principles in Scala](https://www.coursera.org/learn/progfun1) 142 | - [Introduction to Functional Programming](https://www.edx.org/course/introduction-to-functional-programming) 143 | 144 | ## Lists 145 | 146 | - [Awesome Functional Programming by @lucasviola](https://github.com/lucasviola/awesome-functional-programming) 147 | - [Awesome Functional Programming by @xgrommx](https://github.com/xgrommx/awesome-functional-programming) 148 | 149 | ## Community 150 | 151 | - Richard Bird 152 | - Philip Wadler 153 | - Olivier Danvy 154 | - Andrzej Filinski 155 | - Daniel P. Friedman 156 | - Matthias Felleisen 157 | - J. Michael Ashley 158 | - R. Kent Dybvig 159 | - Erik Hilsdale 160 | 161 | ## License 162 | 163 | [MIT](/license) © [TK](https://iamtk.co) 164 | 165 | 166 | -------------------------------------------------------------------------------- /clojure/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Clojure Resources 4 | 5 | ## Functional Clojure 6 | 7 | - [The Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide) 8 | - [Learning Clojure by Practical.li](http://www.practical.li/clojure) 9 | - [Lambda Island](https://lambdaisland.com/) 10 | - [A Year in Clojure](https://blog.taylorwood.io/2017/09/15/year-behind.html) 11 | - ["Running With Scissors: Live Coding With Data" by Stuart Halloway](https://www.youtube.com/watch?v=Qx0-pViyIDU&feature=youtu.be&ab_channel=StrangeLoop) 12 | - [Learn Clojure in Y minutes](https://learnxinyminutes.com/docs/clojure/) 13 | - [Recursion in Clojure](https://imasters.com.br/desenvolvimento/entendendo-recursividade-com-clojure/) 14 | - [Clojure by example](https://kimh.github.io/clojure-by-example) 15 | - [The Ultimate Guide to Clojure Collections](https://purelyfunctional.tv/guide/clojure-collections/) 16 | - [3 Functional Tools: Map, Filter, and Reduce](https://purelyfunctional.tv/courses/3-functional-tools/) 17 | - [Clojure e simplicidade](https://mauricioszabo.wordpress.com/2016/04/07/clojure-e-simplicidade/) 18 | - [Criação de variáveis e contextos léxicos em Clojure](https://blog.bltavares.com/2015/01/28/criacao-de-variaveis-e-contextos-lexicos-em-clojure/) 19 | - [Stuart Sierra blog](https://stuartsierra.com/writing) 20 | - [Repl](https://lambdaisland.com/guides/clojure-repls) 21 | 22 | ## Advanced FP 23 | 24 | - [Learning Clojure: transducers](https://blog.frankel.ch/learning-clojure/6/) 25 | - [Learning Clojure: the arrow and doto macros](https://blog.frankel.ch/learning-clojure/2/) 26 | - [Decoding Clojure code, getting your feet wet](https://blog.frankel.ch/decoding-clojure-code/) 27 | 28 | ## Clojure API 29 | 30 | - [map with partial](https://practicalli.github.io/clojure/thinking-functionally/map-with-partial.html) 31 | - [The Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide) 32 | - [Cheatsheets and information for Clojure/JVM and ClojureScript](https://github.com/jafingerhut/clojure-cheatsheets) 33 | - [Benchmark programs in Clojure](https://github.com/jafingerhut/clojure-benchmarks) 34 | - [Comparators Guide](https://clojure.org/guides/comparators) 35 | - [Sort by](https://github.com/jafingerhut/thalia/blob/master/doc/project-docs/clojure.core-1.5.1/clojure.core/sort-by.md) 36 | - [Repl Driven Development by Stuart Halloway](https://vimeo.com/223309989) 37 | - [Repl Driven Development by Jay Fields](http://blog.jayfields.com/2014/01/repl-driven-development.html) 38 | - [Clojure Destructuring Tutorial and Cheat Sheet](https://gist.github.com/john2x/e1dca953548bfdfb9844) 39 | 40 | ## Tests 41 | 42 | - [API for clojure.test](https://clojure.github.io/clojure/clojure.test-api.html) 43 | - [deftest](https://clojuredocs.org/clojure.test/deftest) 44 | - [Unit Testing in Functional Programming](https://lispcast.com/unit-testing-in-functional-languages/) 45 | - [Clojure.test Cheatsheet](https://github.com/LeandroTk/learning-functional/blob/master/clojure/tests/clojure.test-cheatsheet.pdf) 46 | - [How we test at Nubank](https://www.youtube.com/watch?v=X_PXoiOIdMs&ab_channel=ClojureDays) 47 | - [Testing in Clojure](https://lambdaisland.com/blog/2018-11-02-test-wars-new-hope) 48 | - [Unit Testing by Daniel Gregoire in Clojure Cookbook](https://github.com/clojure-cookbook/clojure-cookbook/blob/master/10_testing/10-01_unit-testing.asciidoc) 49 | 50 | ## Webapps 51 | 52 | - [Clojure Webapps](https://practicalli.github.io/clojure-webapps/) 53 | - [Compojure](https://github.com/weavejester/compojure) 54 | - [Clojure: A live Demonstration of Simplicity That is Production Ready](https://www.youtube.com/watch?v=LcpbBth7FaQ&ab_channel=WixEngineeringTechTalks) 55 | - [A REST API in Clojure](https://blog.interlinked.org/programming/clojure_rest.html) 56 | - [Building a simple HTTP server in Clojure: Part I — Setting up server](https://medium.com/@divyum/building-a-simple-http-server-in-clojure-b8c80fa5035e) 57 | - [Building a simple HTTP server in Clojure: Part II — Adding routes](https://medium.com/@divyum/building-a-simple-http-server-in-clojure-part-ii-adding-routes-3038a81b625f) 58 | - [Building a simple HTTP server in Clojure: Part III — Dockerizing Clojure Application](https://medium.com/@divyum/building-a-simple-http-server-in-clojure-part-iii-dockerizing-clojure-application-1f53a6a90af2) 59 | - [Clojure for OOP Folks: How to Design Clojure Programs](https://speakerdeck.com/stilkov/clojure-for-oop-folks-how-to-design-clojure-programs) 60 | - [Functional TicTacToe](https://www.youtube.com/watch?v=_eO7EsXO2XE) 61 | 62 | ## Better Software 63 | 64 | - [Clojure Design Patterns](http://mishadoff.com/blog/clojure-design-patterns/) 65 | - [Readable Clojure](http://tonsky.me/blog/readable-clojure/) 66 | - [Validations with Schema](https://camdez.com/blog/2015/08/27/practical-data-coercion-with-prismatic-schema/) 67 | - [Component pattern in Clojure](https://www.youtube.com/watch?v=13cmHf_kt-Q&ab_channel=ClojureTV) 68 | - [Clean Clojure: Meaningful Names](http://ecmendenhall.github.io/blog/blog/2013/09/02/clean-clojure-meaningful-names/) 69 | - [Clean Clojure: Small Functions](http://ecmendenhall.github.io/blog/blog/2013/09/05/clean-clojure-functions/) 70 | 71 | ## Challenges 72 | 73 | - [Clojure challenge](https://github.com/rtaboada/challenge) 74 | - [4Clojure Problems](http://www.4clojure.com/problems) 75 | - [Clojure Koans](http://clojurekoans.com/) 76 | - [Exercism](https://exercism.io/my/tracks/clojure) 77 | - [Hacker Rank Functional Path](https://hackerrank.com/domains/fp) 78 | 79 | ## Books 80 | 81 | - [Clojure Applied](https://www.amazon.com/Clojure-Applied-Practitioner-Ben-Vandgrift/dp/1680500740) 82 | - [Clojure data structures and algorithms cookbook](https://www.amazon.com/Clojure-Data-Structures-Algorithms-Cookbook-ebook/dp/B00YSIM3PU/ref=sr_1_1?s=books&ie=UTF8&qid=1548537151&sr=1-1&keywords=Clojure+data+structures+and+algorithms+cookbook) 83 | - [Clojure in action](https://www.amazon.com/Clojure-Action-Amit-Rathore/dp/1617291528/ref=sr_1_1?s=books&ie=UTF8&qid=1548537165&sr=1-1&keywords=Clojure+in+action) 84 | - [Mastering Clojure Macros](https://www.amazon.com/Mastering-Clojure-Macros-Cleaner-Smarter/dp/1941222226/ref=sr_1_1?s=books&ie=UTF8&qid=1548537179&sr=1-1&keywords=Mastering+Clojure+Macros) 85 | - [Practical Clojure](https://www.amazon.com/Practical-Clojure-Experts-Voice-Source/dp/1430272317/ref=sr_1_2?s=books&ie=UTF8&qid=1548537192&sr=1-2&keywords=Practical+Clojure) 86 | - [The Joy of Clojure](https://www.amazon.com/Joy-Clojure-Michael-Fogus/dp/1617291412/ref=sr_1_1?s=books&ie=UTF8&qid=1548537207&sr=1-1&keywords=The+Joy+of+Clojure) 87 | - [Clojure Cookbook](https://www.amazon.com/Clojure-Cookbook-Recipes-Functional-Programming/dp/1449366171/ref=sr_1_1?s=books&ie=UTF8&qid=1548537215&sr=1-1&keywords=Clojure+Cookbook) 88 | 89 | ## Repositories 90 | 91 | - [Purely Functional Data Structures](https://github.com/leonardoborges/purely-functional-data-structures) 92 | - [Clojure Refactoring](https://github.com/tcrayford/clojure-refactoring) 93 | - [Functional Programming for the Object-Oriented Programmer](https://github.com/marick/fp-oo) 94 | 95 | ## Databases 96 | 97 | - [Learn Datalog Today](http://www.learndatalogtoday.org/) 98 | 99 | ## Twitter to Follow 100 | 101 | - [Lambda Island](https://twitter.com/lambdaisland) 102 | - [Clojurecademy](https://twitter.com/clojurecademy) 103 | - [Planet Clojure](https://twitter.com/planetclojure) 104 | - [Clojure Bridge SP](https://twitter.com/ClojureBridgeSP) 105 | - [Clojure Bridge](https://twitter.com/ClojureBridge) 106 | - [Functional Design in Clojure Podcast](http://twitter.com/@clojuredesign) 107 | 108 | 109 | -------------------------------------------------------------------------------- /clojure/basics/boolean.clj: -------------------------------------------------------------------------------- 1 | ;; Ask if the value is nil 2 | (nil? nil) 3 | (nil? 1) 4 | (nil? true) 5 | (nil? false) 6 | (nil? "hello") 7 | 8 | ;; nil and false as logical falsiness 9 | (if nil 10 | (println "not going to print") 11 | (println "going to print")) 12 | 13 | (if false 14 | (println "not going to print") 15 | (println "going to print")) 16 | 17 | ;; the rest of the values as truthy 18 | (if "the truthy" 19 | (println "going to print") 20 | (println "not going to print")) 21 | 22 | (if true 23 | (println "going to print") 24 | (println "not going to print")) 25 | 26 | (if 1 27 | (println "going to print") 28 | (println "not going to print")) 29 | 30 | ;; equality operator: = 31 | (= 1 1) 32 | (= nil nil) 33 | (= 1 2) 34 | 35 | ;; boolean operators: "or" and "and" 36 | (or nil false true "string" 1) 37 | 38 | (or (= 1 1) (= "string" "strong")) 39 | 40 | (and nil false true "string" 1) 41 | 42 | (and (= 1 1) (= "string" "strong")) 43 | -------------------------------------------------------------------------------- /clojure/basics/control-flow.clj: -------------------------------------------------------------------------------- 1 | ;; if-else 2 | (if true "going to return" "not going to return") ;; "going to return" 3 | 4 | (if false "not going to return" "going to return") ;; "going to return" 5 | 6 | (if false "not going to return") ;; nil 7 | 8 | ;; if-do 9 | (if true 10 | (do (println "going to print") 11 | (println "also going to print") 12 | "going to return") 13 | (do (println "not going to print") 14 | "not going to return")) 15 | 16 | ;; if-do 17 | (if false 18 | (do (println "not going to print") 19 | "not going to return") 20 | (do (println "going to print") 21 | (println "also going to print") 22 | "going to return")) 23 | 24 | ;; when 25 | (when true 26 | (println "going to print") 27 | (println "also going to print") 28 | "going to return") 29 | 30 | (when false ;; goint to return nil 31 | (println "going to print") 32 | (println "also going to print") 33 | "going to return") 34 | -------------------------------------------------------------------------------- /clojure/basics/define-functions.clj: -------------------------------------------------------------------------------- 1 | (defn say-hello 2 | "Just say hello" 3 | [name] 4 | (str "Hello " name)) 5 | 6 | (say-hello "TK") 7 | 8 | ; The Docstring: The docstring is a useful way to describe and document your code 9 | (doc map) 10 | 11 | ; Parameters: we can pass zero or more parameters on functions 12 | ; Arity: it is the number of parameters passed on functions 13 | (defn no-parameters 14 | [] 15 | "no parameters") 16 | 17 | (no-parameters) 18 | 19 | (defn one-parameter 20 | [a] 21 | (str "only one parameter: " a)) 22 | 23 | (one-parameter "one") 24 | 25 | (defn two-parameters 26 | [a b] 27 | (str "now two parameters: " a b)) 28 | 29 | (two-parameters 1 2) 30 | 31 | ; arity overloading: a different function body will run depending on the arity 32 | (defn iam 33 | ([name] 34 | (str "I am " name)) 35 | ([name hobby] 36 | (str "I am " name " and I like " hobby))) 37 | 38 | (iam "TK") 39 | (iam "TK" "programming") 40 | 41 | ; rest parameters as a list with & 42 | (defn favorite-things 43 | [name & things] 44 | (str "Hey " name ", here are my favorite things: " 45 | (clojure.string/join ", " things))) 46 | 47 | (favorite-things "TK" "code" "run" "read" "eat") 48 | -------------------------------------------------------------------------------- /clojure/basics/destructuring.clj: -------------------------------------------------------------------------------- 1 | ; bind a name within a collection 2 | (defn my-first 3 | [[first-thing]] 4 | first-thing) 5 | 6 | (my-first [1 2 3]) 7 | 8 | ; naming as many elements as you want and also use rest parameters 9 | (defn chooser 10 | [[first-choice second-choice & rest-of-choices]] 11 | (println first-choice) 12 | (println second-choice) 13 | (println (clojure.string/join ", " rest-of-choices))) 14 | 15 | (chooser ["first choice" "second choice" "third choice" "fourth choice"]) 16 | 17 | ; destructuring maps 18 | (defn show-treasure-location 19 | [{lat :lat lng :lng}] 20 | (println (str "Lat: " lat)) 21 | (println (str "Lng: " lng))) 22 | 23 | (show-treasure-location {:lat 10.22 :lng 90.99}) 24 | -------------------------------------------------------------------------------- /clojure/basics/keywords.clj: -------------------------------------------------------------------------------- 1 | :a 2 | :rumplestiltsken 3 | :34 4 | :_? 5 | 6 | (:a {:a 1 :b 2 :c 3}) 7 | (get {:a 1 :b 2 :c 3} :a) 8 | (:d {:a 1 :b 2 :c 3} "default value") 9 | -------------------------------------------------------------------------------- /clojure/basics/let.clj: -------------------------------------------------------------------------------- 1 | ;; let binds names to value 2 | ;; let it be for this scope 3 | 4 | (let [x 3] 5 | x) 6 | 7 | (def names 8 | ["Tk" "Kazumi" "kaio"]) 9 | 10 | (let [adults (take 2 names)] 11 | adults) 12 | 13 | (let [[tk & rest] names] 14 | [tk rest]) 15 | -------------------------------------------------------------------------------- /clojure/basics/namespaces.clj: -------------------------------------------------------------------------------- 1 | ;; creating a def inside the current namespace 2 | (def great-books ["The Effective Engineer" "POP" "Harry Potter"]) 3 | 4 | ;; creating namespaces 5 | (create-ns 'cheese-taxonomy) 6 | (in-ns 'cheese-taxonomy) 7 | (ns 'cheese-taxonomy) 8 | 9 | ;; refering to other namespace's objects 10 | (in-ns 'some-namespace) 11 | (def first-thing "Like it") 12 | (def second-thing "Love it") 13 | (in-ns 'other-namespace) 14 | 15 | (clojure.core/refer 'some-namespace) 16 | first-thing 17 | second-thing 18 | 19 | ;; using alias for namespaces 20 | (in-ns 'some.namespace) 21 | (def first-thing "Like it") 22 | (def second-thing "Love it") 23 | (in-ns 'other.namespace) 24 | 25 | (clojure.core/alias 'some 'some.namespace) 26 | -------------------------------------------------------------------------------- /clojure/basics/naming-values.clj: -------------------------------------------------------------------------------- 1 | ;; We can bind the name (failed-protagonist-names) to a value (vector) 2 | (def failed-protagonist-names 3 | ["Larry Potter" "Doreen the explorer" "the incredible bulk"]) 4 | 5 | ;; define a function called error-message 6 | ;; with an argument severity 7 | ;; concatenate a string with one of two other strings 8 | (defn error-message 9 | [severity] 10 | (str "OH GOD! IT'S A DISASTER! WE'RE " 11 | (if (= severity :mild) 12 | "MILDLY INCOVINIENT" 13 | "DOOOOMED!"))) 14 | -------------------------------------------------------------------------------- /clojure/basics/recursion.clj: -------------------------------------------------------------------------------- 1 | (first [1 2 3 4 5]) ;; 1 2 | (rest [1 2 3 4 5]) ;; (2 3 4 5) 3 | (empty? [1 2 3 4 5]) 4 | (empty? []) 5 | 6 | ;; I want a function to recursivily print each element of the vector from the start to the end 7 | 8 | (defn recursivily-print 9 | [collection] 10 | (println (first collection)) 11 | (if (empty? collection) 12 | (println "no more elements to print") 13 | (recursivily-print (rest collection)))) 14 | 15 | (recursivily-print [1 2 3 4 5]) 16 | -------------------------------------------------------------------------------- /clojure/clojure_applied/model_your_domain/1.modeling-entities.clj: -------------------------------------------------------------------------------- 1 | ;; using maps as entities 2 | (def earth {:name "Earth" 3 | :moons 1 4 | :volume 1.08321e12 ;; km^3 5 | :mass 5.97219e24 ;; kg 6 | :aphelion 152098232 ;; km, farthest from sun 7 | :perihelion 147098290 ;; km, closest to sun 8 | :type :Planet ;; entity type 9 | }) 10 | 11 | ;; using records as entities 12 | (defrecord Planet [name 13 | moons 14 | volume ;; km^3 15 | mass ;; kg 16 | aphelion ;; km, farthest from sun 17 | perihelion ;; km, closest to sun 18 | ]) 19 | 20 | ;; Position factory function 21 | (def earth 22 | (-> Planet "Earth" 1 1.08321e12 5.97219e24 152098232 147098290)) 23 | 24 | ;; Map factory function 25 | (def earth 26 | (map->Planet {:name "Earth" 27 | :moons 1 28 | :volume 1.08321e12 29 | :mass 5.97219e24 30 | :aphelion 152098232 31 | :perihelion 147098290)) 32 | -------------------------------------------------------------------------------- /clojure/clojure_applied/model_your_domain/2.constructing-entities.clj: -------------------------------------------------------------------------------- 1 | ;; constructing with options 2 | (defn fn-with-opts [n1 n2 & opts]) 3 | 4 | ;; positional destructuring 5 | (defn make-entity [n1 n2 & [n3 n4]]) 6 | 7 | ;; implementing a Money value object 8 | (ns ch1.money) 9 | 10 | (declare validate-same-currency) 11 | 12 | (defrecord Currency [divisor sym desc]) 13 | 14 | (defrecord Money [amount ^Currency currency] 15 | java.lang.Comparable 16 | (compareTo [m1 m2] 17 | (validate-same-currency m1 m2) 18 | (compare (:amount m1) (:amount m2)))) 19 | 20 | (def currencies {:usd (->Currency 100 "USD" "US Dollars") 21 | :eur (->Currency 100 "EUR" "Euro")}) 22 | 23 | (defn- validate-same-currency 24 | [m1 m2] 25 | (or (= (:currency m1) (:currency m2)) 26 | (throw 27 | (ex-info "Currencies do not match." 28 | {:m1 m1 :m2 m2})))) 29 | 30 | (defn =$ 31 | ([m1] true) 32 | ([m1 m2] (zero? (.compareTo m1 m2))) 33 | ([m1 m2 & monies] 34 | (every? zero? (map #(.compareTo m1 %) (conj monies m2))))) 35 | 36 | (defn +$ 37 | ([m1] m1) 38 | ([m1 m2] 39 | (validate-same-currency m1 m2) 40 | (->Money (+ (:amount m1) (:amount m2)) (:currency m1))) 41 | ([m1 m2 & monies] 42 | (reduce +$ m1 (conj monies m2)))) 43 | 44 | (defn *$ [m n] (->Money (* n (:amount m)) (:currency m))) 45 | 46 | (defn make-money 47 | ([] (make-money 0)) 48 | ([amount] (make-money amount :usd)) 49 | ([amount currency] (->Money amount currency))) 50 | 51 | (defn -$ [m1 m2 & monies]) 52 | 53 | (defn allocate [m proportions]) 54 | 55 | (def zero-dollars (make-money 0 :usd)) 56 | 57 | (make-money) 58 | (make-money 1) 59 | (make-money 5 (:eur currencies)) -------------------------------------------------------------------------------- /clojure/clojure_applied/model_your_domain/3.apollo.clj: -------------------------------------------------------------------------------- 1 | (ns ch1.apollo) 2 | 3 | ; 4 | (defn make-mission 5 | [name system launched manned? opts] 6 | (let [{:keys [cm-name ;; command module 7 | lm-name ;; lunar module 8 | orbits 9 | evas]} opts])) 10 | 11 | (def apollo-4 12 | (make-mission "Apollo 4" 13 | "Saturn V" 14 | #inst "1967-11-09T12:00:01-00:00" 15 | false 16 | {:orbits 3})) 17 | ; 18 | 19 | 20 | ; 21 | (def mission-defaults {:orbits 0, :evas 0}) 22 | 23 | (defn make-mission 24 | [name system launched manned? opts] 25 | (let [{:keys [cm-name ;; command module 26 | lm-name ;; lunar module 27 | orbits 28 | evas]} (merge mission-defaults opts)])) 29 | ; 30 | 31 | 32 | ; 33 | (defn make-mission 34 | [name system launched manned? & opts] 35 | (let [{:keys [cm-name ;; command module 36 | lm-name ;; lunar module 37 | orbits 38 | evas]} opts])) 39 | 40 | (def apollo-4 (make-mission "Apollo 4" 41 | "Saturn V" 42 | #inst "1967-11-09T12:00:01-00:00" 43 | false 44 | :orbits 3)) 45 | 46 | (def apollo-11 (make-mission "Apollo 11" 47 | "Saturn V" 48 | #inst "1969-07-16T13:32:00-00:00" true 49 | :cm-name "Columbia" 50 | :lm-name "Eagle" 51 | :orbits 30 52 | :evas 1)) 53 | ; 54 | 55 | ; 56 | (defn make-mission 57 | [name system launched manned? & opts] 58 | (let [{:keys [cm-name ;; command module 59 | lm-name ;; lunar module 60 | orbits 61 | evas] 62 | :or {orbits 0, evas 0}} opts] ;; default to 0 63 | )) 64 | 65 | (def apollo-4 (make-mission "Apollo 4" 66 | "Saturn V" 67 | #inst "1967-11-09T12:00:01-00:00" 68 | false 69 | :orbits 3)) 70 | ; 71 | 72 | ; 73 | (defn euclidean-norm [ecc-vector]) 74 | 75 | (defrecord Planet 76 | [name moons volume mass aphelion perihelion orbital-eccentricity]) 77 | 78 | (defn make-planet 79 | "Make a planet from field values and an eccentricity vector" 80 | [name moons volume mass aphelion perhelion ecc-vector] 81 | (->Planet 82 | name moons volume mass aphelion perhelion 83 | (euclidean-norm ecc-vector))) 84 | ; -------------------------------------------------------------------------------- /clojure/data_structures/atom.clj: -------------------------------------------------------------------------------- 1 | ;; The world is mutable 2 | 3 | (def n (atom 10)) 4 | 5 | (swap! n 6 | (fn [old-n] (+ old-n 10))) 7 | 8 | (deref n) 9 | -------------------------------------------------------------------------------- /clojure/data_structures/data-structures.clj: -------------------------------------------------------------------------------- 1 | ;; numerical 2 | 90 3 | 10.5 4 | 1/5 5 | 6 | ;; strings 7 | "Leandro TK" 8 | "\"Not Leandro TK\"" 9 | 'single quote is not a string' 10 | 11 | ;; maps 12 | {} 13 | {:my-key "my string value"} 14 | {"string-key" +} ;; string as key and + function as the value 15 | {:user {:first-name "Leandro" :last-name "TK"}} ;; nested map 16 | (hash-map :a 1 :b 2) ;; using hash-map function to create a new map 17 | (get {:name "TK"} :name) ;; map lookup by key 18 | (get-in {:user {:first-name "Leandro" :last-name "TK"}} [:user :last-name]) ;; map lookup on nested map 19 | ({:name "TK"} :name) ;; treating maps as function to do lookups 20 | -------------------------------------------------------------------------------- /clojure/data_structures/hash-map.clj: -------------------------------------------------------------------------------- 1 | {:a 1 2 | :b 2 3 | :c 3} 4 | 5 | {:a 1 6 | :a 2} ; throws a exception: keys need to be unique 7 | 8 | ; creating a hash with hash-map function 9 | (hash-map :a 1 :b 2); {:a 1 :b 2} 10 | 11 | ; get value by key 12 | ({:a 1 :b 2} :b) ; 2 13 | -------------------------------------------------------------------------------- /clojure/data_structures/laziness.clj: -------------------------------------------------------------------------------- 1 | ; Clojure is lazy in the way it handles its sequence types 2 | 3 | (defn if-chain [x y z] 4 | (if x 5 | (if y 6 | (if z 7 | (do 8 | (println "Made it!") 9 | :all-truthy))))) 10 | 11 | (if-chain true true true) 12 | 13 | ; The same implementation but using the `and` macro 14 | 15 | (defn if-chain [x y z] 16 | (and x y z (do (println "Made it!") :all-truthy))) 17 | 18 | (if-chain true true true) 19 | (if-chain () true "String") 20 | (if-chain true false true) 21 | 22 | (defn rec-step [[x & xs]] 23 | (if x 24 | [x (rec-step xs)] 25 | [])) 26 | 27 | (rec-step [1 2 3 4]) 28 | (rec-step (range 200000)) ;; java.lang.StackOverflowError 29 | -------------------------------------------------------------------------------- /clojure/data_structures/lists.clj: -------------------------------------------------------------------------------- 1 | '(1 2 3 4 5) 2 | (nth '(1 2 3 4 5) 2) 3 | (nth '(1 2 3 4 5) 4) 4 | (list 1 "two" [1 2 3]) 5 | (conj '(2 3 4) 1) ; Add element as the first list item 6 | -------------------------------------------------------------------------------- /clojure/data_structures/persistent-data-structures.clj: -------------------------------------------------------------------------------- 1 | (defn new-tree [val L R] 2 | {:val val 3 | :L L 4 | :R R}) 5 | 6 | (defn build-tree [tree value] 7 | (cond 8 | (nil? tree) {:val value :L nil :R nil} 9 | (< value (:val tree)) (new-tree (:val tree) 10 | (build-tree (:L tree) value) 11 | (:R tree)) 12 | :else (new-tree (:val tree) 13 | (:L tree) 14 | (build-tree (:R tree) value)))) 15 | 16 | (def tree (build-tree nil 5)) 17 | (def tree (build-tree tree 4)) 18 | (def tree (build-tree tree 2)) 19 | (def tree (build-tree tree 1)) 20 | (def tree (build-tree tree 6)) 21 | 22 | (defn print-tree [tree] 23 | (when tree 24 | (concat (print-tree (:L tree)) 25 | [(:val tree)] 26 | (print-tree (:R tree))))) 27 | 28 | (print-tree tree) 29 | -------------------------------------------------------------------------------- /clojure/data_structures/sets.clj: -------------------------------------------------------------------------------- 1 | ; unique values 2 | #{"TK" 26 :software-engineer} 3 | (hash-set 1 2 3 4 4 3) ; #{1 2 3 4} 4 | (set [1 2 3 4 1]) 5 | 6 | ; do not add a value that already exists in the set 7 | (conj #{1 2 3} 1) 8 | 9 | ; contains? returns true or false 10 | (contains? #{1 2 3} 2) 11 | (contains? #{1 2 3} 0) 12 | 13 | ; get returns the found element (or nil if not found) 14 | (get #{1 2 3} 1) 15 | (get #{1 2 3} 4) 16 | 17 | ; keyword works like the get function 18 | (:1 #{:1 :2 :3}) 19 | (:a #{:1 :2 :3}) 20 | -------------------------------------------------------------------------------- /clojure/data_structures/vectors.clj: -------------------------------------------------------------------------------- 1 | ; "syntax" 2 | [1 2 3] ; [1 2 3] 3 | 4 | ; get the first element using index 5 | ([1 2 3] 0) ; 1 6 | 7 | ; get the first element using get 8 | (get [1 2 3] 0) ; 1 9 | 10 | ; get the second element 11 | (get [1 {:first-name "Leandro" :last-name "TK"} 2] 1) ; {:first-name "Leandro" :last-name "TK"} 12 | 13 | ; build a vector from elements 14 | (vector "a" "new" "vector" "of" "strings") ; ["a" "new" "vector" "of" "strings"] 15 | 16 | ; add a new element to the vector 17 | (conj [1 2 3] 4) ; [1 2 3 4] 18 | 19 | ; vectors evaluate each element before building 20 | [1 :x (+ 1 1)] ; [1 :x 2] 21 | ; (eval [1 :x (+ 1 1)]) 22 | ; [(eval 1) (eval :x) (eval (+ 1 1))] 23 | ; [1 :x 2] 24 | -------------------------------------------------------------------------------- /clojure/functional/composition.clj: -------------------------------------------------------------------------------- 1 | (def fifth (comp first rest rest rest rest)) 2 | 3 | (fifth [1 2 3 4 5]) 4 | -------------------------------------------------------------------------------- /clojure/functions/anonymous-functions.clj: -------------------------------------------------------------------------------- 1 | ; functions don't need to have names 2 | (fn [params-list] 3 | "something") 4 | 5 | (map (fn [name] (str "Hello " name)) ["TK" "Kazumi" "Kaio"]) 6 | 7 | ((fn [n] (* n 2)) 8) 8 | 9 | (#(* % 8) 3) 10 | 11 | (map #(str "Hello " %) ["TK" "Kazumi" "Kaio"]) 12 | -------------------------------------------------------------------------------- /clojure/functions/comparators.clj: -------------------------------------------------------------------------------- 1 | ;; Resource: https://clojure.org/guides/comparators 2 | ;; compare works for many types of values, ordering them in one particular way: 3 | ;; - increasing numeric order for numbers; 4 | ;; - lexicographic order (aka dictionary order) for strings, symbols, and keywords; 5 | ;; - shortest-to-longest order by Clojure vectors, with lexicographic ordering among equal length vectors 6 | 7 | ;; reverse order 8 | (defn reverse-cmp 9 | [a b] 10 | (compare b a)) 11 | 12 | (sort reverse-cmp [1 2 3 4]) 13 | 14 | ;; using Clojure’s #() notation 15 | (sort #(compare %2 %1) [1 2 3 4]) 16 | 17 | ;; Multi-field comparators 18 | (def john1 {:name "John", :salary 35000.00, :company "Acme"}) 19 | (def mary {:name "Mary", :salary 35000.00, :company "Mars Inc"}) 20 | (def john2 {:name "John", :salary 40000.00, :company "Venus Co"}) 21 | (def john3 {:name "John", :salary 30000.00, :company "Asteroids-R-Us"}) 22 | (def people [john1 mary john2 john3]) 23 | 24 | (defn by-salary-name-company 25 | [x y] 26 | (let [c (compare (:salary y) (:salary x))] 27 | (if (not= c 0) 28 | c 29 | (let [c (compare (:name x) (:name y))] 30 | (if (not= c 0) 31 | c 32 | (compare (:company x) (:company y))))))) 33 | 34 | (sort by-salary-name-company people) 35 | 36 | ;; short verstion of by-salary-name-company 37 | (defn by-salary-name-company 38 | [x y] 39 | (compare [(:salary y) (:name x) (:company x)] 40 | [(:salary x) (:name y) (:company y)])) 41 | 42 | (sort by-salary-name-company people) 43 | -------------------------------------------------------------------------------- /clojure/functions/core-functions.clj: -------------------------------------------------------------------------------- 1 | ;; Using map as a sequence function for collections 2 | 3 | (defn titleize 4 | [topic] 5 | (str topic " for the Brave and True")) 6 | 7 | (map titleize ["Hamsters" "Ragnarok"]) 8 | ; => ("Hamsters for the Brave and True" "Ragnarok for the Brave and True") 9 | 10 | (map titleize '("Empathy" "Decorating")) 11 | ; => ("Empathy for the Brave and True" "Decorating for the Brave and True") 12 | 13 | (map titleize #{"Elbows" "Soap Carving"}) 14 | ; => ("Elbows for the Brave and True" "Soap Carving for the Brave and True") 15 | 16 | (map #(titleize (second %)) {:uncomfortable-thing "Winking"}) 17 | ; => ("Winking for the Brave and True") 18 | 19 | (defn titleize-hash 20 | [hash] 21 | (titleize (second hash))) 22 | 23 | (map (partial titleize-hash) {:something "Something" 24 | :other-thing "Other"}) 25 | 26 | (def human-consumption [8.1 7.3 6.6 5.0]) 27 | (def critter-consumption [0.0 0.2 0.3 1.1]) 28 | (defn unify-diet-data 29 | [human critter] 30 | {:human human 31 | :critter critter}) 32 | 33 | (map unify-diet-data human-consumption critter-consumption) 34 | ; ({:human 8.1, :critter 0.0} 35 | ; {:human 7.3, :critter 0.2} 36 | ; {:human 6.6, :critter 0.3} 37 | ; {:human 5.0, :critter 1.1}) 38 | 39 | ; Reduce 40 | (reduce (fn [new-map [key val]] 41 | (assoc new-map key (inc val))) 42 | {} 43 | {:max 30 :min 10}) 44 | ; => {:max 31, :min 11} 45 | 46 | ; slugify function 47 | 48 | (defn slugify [text] 49 | (-> text 50 | (clojure.string/trim) 51 | (clojure.string/lower-case) 52 | (clojure.string/replace " " "-"))) 53 | 54 | (def text " OLA mundao ") 55 | 56 | (clojure.string/trim text) 57 | (clojure.string/lower-case text) 58 | (clojure.string/replace text " " "-") 59 | 60 | (slugify text) 61 | -------------------------------------------------------------------------------- /clojure/functions/filter.clj: -------------------------------------------------------------------------------- 1 | ;; (filter f coll) | Clojure Syntax for filter function 2 | ;; Keep just the elements that are true based on the function (predicate) passed 3 | 4 | ;; f = function/predicate 5 | ;; coll = collection 6 | 7 | ;; Some examples: 8 | ;; (filter pasta? pot) ;; strainer 9 | ;; (filter water? pot) ;; coffee 10 | ;; (filter air? house) ;; aircondition 11 | 12 | ;; Using even? function as a filter example 13 | ;; original collection: (0 1 2 3 4 5 6 7 8 9) 14 | ;; result of filter function: (0 2 4 6 8) 15 | (filter even? (range 0 10)) 16 | 17 | ;; We can also use keywords as functions for filter 18 | ;; This code will result in: ({:a 1} {:a 2}) 19 | ;; (:a {:a 1}) returns 1, and it is true 20 | ;; (:a {:a 2}) returns 2, and it is true 21 | ;; (:a {:b 10}) returns nil, and it is false 22 | ;; (:a {:a false}) returns false, and it is false 23 | (filter :a 24 | [{:a 1} 25 | {:a 2} 26 | {:b 10} 27 | {:a false}]) 28 | 29 | ;; (mod x 3): if it is zero, x is divisible by 3 30 | ;; (zero? x): asks if x is zero 31 | ;; (not result): revert the result value. If it is true, it turns to false. Otherwise, true. 32 | ;; In this example, we will filter only the numbers that are not divisible by 3 33 | ;; original collection: (0 1 2 3 4 5 6 7 8 9) 34 | ;; result of filter function: (1 2 4 5 7 8) 35 | (filter 36 | (fn [x] (not (zero? (mod x 3)))) 37 | (range 0 10)) 38 | -------------------------------------------------------------------------------- /clojure/functions/function-body.clj: -------------------------------------------------------------------------------- 1 | ; Clojure automatically returns the last form evaluated. 2 | (defn an-example 3 | [] 4 | (+ 1 1) 5 | 10 6 | "TK") 7 | 8 | (an-example) 9 | 10 | ; using conditional within a function 11 | (defn number-comment 12 | [number] 13 | (if (> number 5) 14 | (println "greater than five") 15 | (println "less or equal to five"))) 16 | 17 | (number-comment 5) 18 | (number-comment 6) 19 | -------------------------------------------------------------------------------- /clojure/functions/functional.clj: -------------------------------------------------------------------------------- 1 | ;; A pure function: use only the passed parameter 2 | ;; Pure Functions Have No Side Effects 3 | (defn wisdom 4 | [words] 5 | (str words ", Daniel-san")) 6 | 7 | (wisdom "Always bathe on Fridays") 8 | 9 | ;; Not a pure function because it uses an external global object 10 | (def PI 3.14) 11 | 12 | (defn calculate-area 13 | [radius] 14 | (* radius radius PI)) 15 | 16 | (calculate-area 10) ;; returns 314.0 17 | 18 | ;; pure function because it uses only parameters passed as arguments 19 | (def PI 3.14) 20 | 21 | (defn calculate-area 22 | [radius, PI] 23 | (* radius radius PI)) 24 | 25 | (calculate-area 10 PI) ;; returns 314.0 26 | 27 | ;; Not pure: it uses the global variable and modify the variable 28 | (def counter 1) 29 | 30 | (defn increase-counter 31 | [value] 32 | (def counter (inc value))) 33 | 34 | (increase-counter counter) 35 | 36 | ;; pure function: returns the value increased by 1 37 | (def counter 1) 38 | 39 | (defn increase-counter 40 | [value] 41 | (inc value)) 42 | 43 | (increase-counter counter) ;; 2 44 | counter ;; 1 45 | 46 | ;; impure function: reads an external file 47 | (defn characters-counter 48 | [text] 49 | (str "Character count: " (count text))) 50 | 51 | (defn analyze-file 52 | [filename] 53 | (characters-counter (slurp filename))) 54 | 55 | (analyze-file "test.txt") 56 | 57 | ;; using a referentially transparent function, you never have to consider what 58 | ;; possible external conditions could affect the return value of the function. 59 | 60 | ;; immutability 61 | -------------------------------------------------------------------------------- /clojure/functions/functions.clj: -------------------------------------------------------------------------------- 1 | ; functions syntax: opening parenthesis, operator, operands, closing parenthesis 2 | 3 | ; calling functions 4 | (+ 1 2 3 4 5) 5 | (* 9 9) 6 | (first [1 2 3 4 5]) 7 | 8 | ; the return value of "or" function is the first truthy value. 9 | ; In this case, the value returned is the string representation of the plus function 10 | (or + -) 11 | 12 | ; using an expression as an operator of another expression 13 | ((or + -) 1 2 3) 14 | 15 | ; functions that can either take a function as an argument or return a function are called higher-order functions 16 | ; "inc" function increments the value passed 17 | (inc 1.1) 18 | 19 | ; "map" function creates a new list by applying a function to each member of a collection 20 | (map inc [1 2 3 4]) 21 | 22 | ; playing with functions within functions 23 | (+ (inc 199) (/ 100 (- 7 2))) 24 | 25 | (zipmap [:a :b :c] [1 2 3]) ; {:a 1 :b 2 :c 3} 26 | -------------------------------------------------------------------------------- /clojure/functions/high-order-functions.clj: -------------------------------------------------------------------------------- 1 | (map inc [0 1 2 3 4 5]) 2 | (range 1 10) 3 | (reduce + (range 1 10)) 4 | (reduce + '(1 2 3 4 5 6 7 8 9)) 5 | (take 10 (range)) 6 | (filter 7 | even? 8 | [0 1 2 3 4 5 6 7 8 9]) 9 | 10 | ; function as value --> as arguments 11 | 12 | (def numbers [1 3 2 5 4 6 7]) 13 | 14 | (sort numbers) ; (1 2 3 4 5 6 7) 15 | (sort > numbers) ; (7 6 5 4 3 2 1) 16 | 17 | ; sort-by function used to preprocess each sortable element 18 | ; into something that is mutually comparable 19 | 20 | (sort-by second [[:a 2] [:b 7] [:c 3] [:d 6]]) ; ([:a 2] [:c 3] [:d 6] [:b 7]) 21 | (sort-by str ["c" "aa" "a" "b" 1 34 2]) ; (1 2 34 "a" "aa" "b" "c") 22 | 23 | ; with comparable function 24 | (sort-by second > [[:a 2] [:b 7] [:c 3] [:d 6]]) ; ([:b 7] [:d 6] [:c 3] [:a 2]) 25 | 26 | (sort-by :age [{:age 99}, {:age 13}, {:age 7}]) ; ({:age 7} {:age 13} {:age 99}) 27 | 28 | ; Exercise: sort by the plays/loved ratio 29 | (def plays [{:band "Burial", :plays 979, :loved 9} 30 | {:band "Eno", :plays 2333, :loved 15} 31 | {:band "Bill Evans", :plays 979, :loved 9} 32 | {:band "Magma", :plays 2665, :loved 31}]) 33 | 34 | (def sort-by-loved-ratio (partial sort-by #(/ (:plays %) (:loved %)))) 35 | (sort-by-loved-ratio plays) 36 | ; ({:band "Magma" :plays 2665 :loved 31} 37 | ; {:band "Burial" :plays 979 :loved 9} 38 | ; {:band "Bill Evans" :plays 979 :loved 9} 39 | ; {:band "Eno" :plays 2333 :loved 15}) 40 | 41 | (sort-by (columns [:plays :loved :band]) plays) 42 | 43 | 44 | (map {:band "Bill Evans", :plays 979, :loved 9} [:plays :loved :band]) 45 | 46 | ({:band "Bill Evans", :plays 979, :loved 9} :plays) 47 | -------------------------------------------------------------------------------- /clojure/functions/polymorphism.clj: -------------------------------------------------------------------------------- 1 | (defn poly 2 | ([] (poly "without argument")) 3 | ([arg] (println arg))) 4 | 5 | (poly) 6 | (poly "an arg") 7 | -------------------------------------------------------------------------------- /clojure/functions/reduce.clj: -------------------------------------------------------------------------------- 1 | ;; Reduce: 2 | ;; - Assemble 3 | ;; - Taking a collection of things and put into one thing as the final product 4 | 5 | ;; Clojure Syntax: (reduce f start coll) 6 | ;; f = function of two arguments 7 | ;; start = initial value 8 | ;; coll = collection 9 | 10 | ;; Some real world examples: 11 | ;; (reduce glue paper noodles) 12 | ;; (reduce paint paper paints) 13 | 14 | ;; (0 1 2 3 4 5 6 7 8 9) 15 | ;; (+ 0 0) --> result: 0 16 | ;; (+ 0 1) --> result: 1 17 | ;; (+ 1 2) --> result: 3 18 | ;; ... 19 | ;; 45 20 | (reduce + 0 (range 0 10)) 21 | 22 | ;; (1 2 3 4 5 6 7 8 9) 23 | ;; (+ 1 1) --> result: 1 24 | ;; (+ 1 1) --> result: 1 25 | ;; (+ 1 2) --> result: 2 26 | ;; ... 27 | ;; 362880 28 | (reduce * 1 (range 1 10)) 29 | 30 | ;; build a into function 31 | ;; receive a recipient (collection) and a values (another collection) 32 | ;; and returns a new collection with a combination of the two given collection 33 | ;; recipient: (1 2 3) 34 | ;; values: (4 5 6) 35 | ;; (conj (1 2 3) 4) --> (1 2 3 4) 36 | ;; (conj (1 2 3 4) 5) --> (1 2 3 4 5) 37 | ;; (conj (1 2 3 4 5) 6) --> (1 2 3 4 5 6) 38 | (defn new-into 39 | [recipient values] 40 | (reduce conj 41 | recipient values)) 42 | -------------------------------------------------------------------------------- /clojure/functions/returning-functions.clj: -------------------------------------------------------------------------------- 1 | ;; The returned functions are closures, 2 | ;; which means that they can access all the variables that were in scope when the function was created 3 | 4 | (defn inc-maker 5 | "Create a custom incrementor" 6 | [inc-by] 7 | #(+ % inc-by)) 8 | 9 | (def inc3 (inc-maker 3)) 10 | 11 | (inc3 7) ;; 10 12 | -------------------------------------------------------------------------------- /elixir/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Elixir 4 | 5 | ## Courses 6 | 7 | - [Elixir School](https://elixirschool.com/en/) 8 | - [PATTERN MATCHING Course](https://thinkingelixir.com/available-courses/pattern-matching/) 9 | 10 | 11 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/01.thinking-functional/01.immutable_data.ex: -------------------------------------------------------------------------------- 1 | list = [1, 2, 3, 4] 2 | 3 | list_without_last = List.delete_at(list, -1) 4 | IO.inspect list_without_last # [1, 2, 3] 5 | 6 | list_with_one_more = list ++ [1] 7 | IO.inspect list_with_one_more # [1, 2, 3, 4, 1] 8 | 9 | # the list value is immutable 10 | IO.inspect list # [1, 2, 3, 4] 11 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/01.thinking-functional/02.functions.ex: -------------------------------------------------------------------------------- 1 | # simple functions 2 | add2 = fn (n) -> n + 2 end 3 | result = add2.(2) 4 | IO.inspect result 5 | 6 | # passing functions as arguments 7 | animals = ["cat", "dog", "fish"] 8 | uppercase_animals = Enum.map(animals, &String.upcase/1) 9 | IO.inspect uppercase_animals 10 | 11 | # using pipes to process data 12 | def capitalize_words(title) do 13 | title 14 | |> String.split 15 | |> capitalize_all 16 | |> join_with_whitespace 17 | end 18 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/02.variables-and-functions/01.values.ex: -------------------------------------------------------------------------------- 1 | # values 2 | "I'm TK" # string 3 | 27 # integer 4 | 10.5 # real number 5 | true # boolean 6 | :ok # atom 7 | {:name, :age} # tuple 8 | [1, 2] # list 9 | %{name: "TK", age: 27} # map 10 | nil # nil 11 | 12 | # value expressions 13 | 37 + 3.7 # 40.7 14 | (2 + 2) * 3 # 12 15 | 2 + 2 * 3 # 8 16 | 17 | # logical expression 18 | true and true # true 19 | true or false # true 20 | true and false # false 21 | false or false # false 22 | 23 | 1 && "I'm TK" # "I'm TK" 24 | "Hello, Word!" && true # true 25 | nil || 1 # 1 26 | 1 || "hi" # 1 27 | 28 | # Anonymous Functions 29 | hello = fn name -> "Hello " <> name <> "!" end 30 | IO.inspect hello.("TK") 31 | IO.inspect hello.("Dan") 32 | IO.inspect hello.("Kaio") 33 | 34 | # using string interpolation 35 | hello = fn name -> "Hello #{name}!" end 36 | IO.inspect hello.("TK") 37 | IO.inspect hello.("Dan") 38 | IO.inspect hello.("Kaio") 39 | 40 | # function without arguments 41 | one_plus_one = fn -> 1 + 1 end 42 | IO.inspect one_plus_one.() # 2 43 | 44 | # functions as value 45 | total_price = fn price, fee -> price * fee.(price) end 46 | flat_fee = fn price -> 5 end 47 | proportional_fee = fn price -> price * 0.12 end 48 | 49 | IO.inspect total_price.(1000, flat_fee) # 1005 50 | IO.inspect total_price.(1000, proportional_fee) # 1120.0 51 | 52 | # working with modules 53 | defmodule Checkout do 54 | def total_cost(price, tax_rate) do 55 | price * (tax_rate + 1) 56 | end 57 | end 58 | 59 | Checkout.total_cost(100, 0.2) # 120.0 60 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/02.variables-and-functions/exercises/01.ex: -------------------------------------------------------------------------------- 1 | # Create an expression that solves the following problem: 2 | # Sarah has bought ten slices of bread for ten cents each, 3 | # three bottles of milk for two dollars each, and a cake for fifteen dollars. 4 | # How many dollars has Sarah spent? 5 | 6 | 10 * 0.10 + 3 * 2 + 15 # 22.0 7 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/02.variables-and-functions/exercises/02.ex: -------------------------------------------------------------------------------- 1 | # Bob has traveled 200 km in four hours. 2 | # Using variables, print a message showing his travel distance, time, and average velocity. 3 | 4 | distance = 200 5 | time = 4 6 | average_velocity = 200 / 4 7 | 8 | IO.inspect distance 9 | IO.inspect time 10 | IO.inspect average_velocity 11 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/02.variables-and-functions/exercises/03.ex: -------------------------------------------------------------------------------- 1 | # Build an anonymous function that applies a tax of 12% to a given price. 2 | # It should print a message with the new price and tax value. 3 | # Bind the anonymous function to a variable called apply_tax. 4 | # You should use apply_tax with Enum.each/2, like in the following example. 5 | 6 | print = fn total_price, taxed_price -> 7 | IO.puts "Price: #{total_price} - Tax: #{taxed_price}" 8 | end 9 | 10 | apply_tax = fn price -> 11 | taxed_price = price * 0.12 12 | total_price = price + taxed_price 13 | print.(total_price, taxed_price) 14 | 15 | total_price 16 | end 17 | 18 | Enum.each [12.5, 30.99, 250.49, 18.80], apply_tax 19 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/02.variables-and-functions/exercises/04.ex: -------------------------------------------------------------------------------- 1 | defmodule MatchstickFactory do 2 | def boxes(matchsticks) do 3 | big = div(matchsticks, 50) 4 | remaining_after_big = rem(matchsticks, 50) 5 | 6 | medium = div(remaining_after_big, 20) 7 | remaining_after_medium = rem(remaining_after_big, 20) 8 | 9 | small = div(remaining_after_medium, 5) 10 | remaining_matchsticks = rem(remaining_after_medium, 5) 11 | 12 | %{ 13 | big: big, 14 | medium: medium, 15 | small: small, 16 | remaining_matchsticks: remaining_matchsticks 17 | } 18 | end 19 | end 20 | 21 | IO.inspect MatchstickFactory.boxes(98) 22 | IO.inspect MatchstickFactory.boxes(39) 23 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/03.using-pattern-matching-to-control-the-program-flow/01.equal_operator.ex: -------------------------------------------------------------------------------- 1 | 1 = 1 # ok 2 | 1 = 2 # raises an error 3 | x = 1 # ok 4 | 1 = x # ok 5 | 2 = x # raises an error 6 | -------------------------------------------------------------------------------- /elixir/learn-fp-with-elixir/03.using-pattern-matching-to-control-the-program-flow/02.destructuring.ex: -------------------------------------------------------------------------------- 1 | # strings 2 | "Authentication: " <> credentials = "Authentication: Basic dXNlcjpwYXNz" 3 | IO.inspect credentials 4 | 5 | # tuples 6 | {a, b, c} = {1, 2, 3} 7 | IO.inspect a 8 | IO.inspect b 9 | IO.inspect c 10 | 11 | # lists 12 | [a, b, c] = [1, 2, 3] 13 | IO.inspect a 14 | IO.inspect b 15 | IO.inspect c 16 | 17 | [_, x, _] = [1, 2, 3] # this _ operator is called wild card 18 | IO.inspect x 19 | 20 | [head | rest] = [1, 2, 3, 4, 5] 21 | IO.inspect head # 1 22 | IO.inspect rest # [2, 3, 4, 5] 23 | 24 | [first, second | rest] = [1, 2, 3, 4, 5] 25 | IO.inspect first # 1 26 | IO.inspect second # 2 27 | IO.inspect rest # [2, 3, 4, 5] 28 | 29 | [head | rest] = [:a] 30 | IO.inspect head # :a 31 | IO.inspect rest # [] 32 | 33 | # maps 34 | user_signup = %{username: "TK", email: "tk@mail.com", password: "123123123"} 35 | IO.inspect user_signup 36 | 37 | user_signup = %{:username => "TK", :email => "tk@mail.com", :password => "123123123"} # another map syntax 38 | 39 | %{email: email} = user_signup 40 | IO.inspect email 41 | 42 | %{username: username = "TK"} = user_signup 43 | IO.inspect username 44 | -------------------------------------------------------------------------------- /haskell/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Haskell 4 | 5 | ## Table of Content 6 | 7 | - [Videos](#videos) 8 | - [Courses](#courses) 9 | - [Books](#books) 10 | 11 | ## Videos 12 | 13 | - [Haskell 101 @ Google](https://www.youtube.com/watch?v=cTN1Qar4HSw&feature=youtu.be) 14 | - [Haskell 102 @ Google](https://www.youtube.com/watch?v=Ug9yJnOYR4U&feature=youtu.be) 15 | 16 | ## Courses 17 | 18 | - [Functional Programming - edX](https://www.edx.org/course/introduction-to-functional-programming) 19 | 20 | ## Books 21 | 22 | - [The Joy of Haskell](https://joyofhaskell.com/) 23 | 24 | 25 | -------------------------------------------------------------------------------- /haskell/basics.hs: -------------------------------------------------------------------------------- 1 | head [1, 2, 3, 4, 5] -- get the first: 1 2 | tail [1, 2, 3, 4, 5] -- get the last: 5 3 | take 3 [1, 2, 3, 4, 5] -- get the first n elements: [1, 2, 3] 4 | drop 3 [1, 2, 3, 4, 5] -- remove the first n element: [4, 5] 5 | length [1, 2, 3, 4, 5] -- 5 6 | sum [1, 2, 3, 4, 5] -- sum all elements in the list: 15 7 | product [1, 2, 3, 4, 5] -- product all elements in the list: 120 8 | [1, 2, 3] ++ [4, 5] -- append two lists: [1, 2, 3, 4, 5] 9 | reverse [1, 2, 3, 4, 5] -- reverse all elements in the list: [5, 4, 3, 2, 1] 10 | -------------------------------------------------------------------------------- /haskell/function_application.hs: -------------------------------------------------------------------------------- 1 | f a + b -- meaning f(a) + b, rather than f(a + b) -- `f` apply to `a` 2 | f a b -- f(a, b) 3 | f (g x) -- f(g(x)) 4 | f x (g y) -- f(x, g(y)) 5 | f x * g y -- f(x) * g(y) 6 | -------------------------------------------------------------------------------- /javascript/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # JavaScript Functional Programming 4 | 5 | ## Table of Content 6 | 7 | - [JavaScript](https://github.com/leandrotk/functional-programming-learning-path/tree/master/javascript/javascript/README.md) 8 | - [Beginner](#beginner) 9 | - [Intermediate](#intermediate) 10 | - [Advanced](#advanced) 11 | - [With React](#with-react) 12 | - [Courses](#courses) 13 | - [Books](#books) 14 | 15 | ## Beginner 16 | 17 | - [A repo. that demonstrates use of functional programming in javascript](https://github.com/divyanshu-rawat/Functional-Programming-JS) 18 | - [Entendendo Programação Funcional em JavaScript de uma vez](https://medium.com/tableless/entendendo-programa%C3%A7%C3%A3o-funcional-em-javascript-de-uma-vez-c676489be08b) 19 | - [Two Years of Functional Programming in JavaScript: Lessons Learned](https://hackernoon.com/two-years-of-functional-programming-in-javascript-lessons-learned-1851667c726) 20 | - [Javascript Funcional](https://www.youtube.com/watch?v=k07DBTYj9w8&ab_channel=iMasters) 21 | - [Flavio Corpa's collection of FP's JavaScript functions](https://github.com/kutyel/functional-programming) 22 | - [JavaScript Testing: Unit vs Functional vs Integration Tests](https://www.sitepoint.com/javascript-testing-unit-functional-integration/) 23 | - [Gist: Usages for ES6 destructuring](https://gist.github.com/mikaelbr/9900818) 24 | - [Functional Programming in JavaScript series by mpj](https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84) 25 | - [Pure functions in Javascript](http://nicoespeon.com/en/2015/01/pure-functions-javascript/) 26 | - [Concepts of Functional Programming in Javascript](https://medium.com/the-renaissance-developer/concepts-of-functional-programming-in-javascript-6bc84220d2aa) 27 | - [Functional Programming Basics In ES6](https://www.youtube.com/watch?v=FYXpOjwYzcs&ab_channel=CodingTech) 28 | - [Functional programming with Javascript](https://stephen-young.me.uk/2013/01/20/functional-programming-with-javascript.html) 29 | - [Map, Filter, Reduce in Typescript](https://www.matthewgerstman.com/map-filter-reduce/) 30 | 31 | ## Intermediate 32 | 33 | - [Javascript- Currying VS Partial Application](https://codeburst.io/javascript-currying-vs-partial-application-4db5b2442be8) 34 | - [Variable length currying in JavaScript](https://medium.com/@Charles_Stover/variable-length-currying-in-javascript-7f7bb7bdad8b) 35 | 36 | ## Advanced 37 | 38 | - [Adding pipelines to JavaScript](https://blog.logrocket.com/adding-pipelines-to-javascript-f79ae7311574) 39 | - [Functors by mpj](https://www.youtube.com/watch?v=DisD9ftUyCk) 40 | - [Functors in Javascript](http://functionaljavascript.blogspot.com.br/2013/07/functors.html) 41 | - [JavaScript and Type Thinking](https://medium.com/@yelouafi/javascript-and-type-thinking-735edddc388d) 42 | - [Functional Composition in Javascript](https://joecortopassi.com/articles/functional-composition-in-javascript/) 43 | - [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) 44 | - [Monads in JavaScript](https://curiosity-driven.org/monads-in-javascript) 45 | - [JavaScript Monads Made Simple](https://medium.com/javascript-scene/javascript-monads-made-simple-7856be57bfe8) 46 | 47 | ## With React 48 | 49 | - [An intro to Functional Programming in JavaScript and React](https://medium.com/@agm1984/an-overview-of-functional-programming-in-javascript-and-react-part-one-10d75b509e9e) 50 | - [Functional Programming in JavaScript and React (Part Two)](https://medium.com/@agm1984/functional-programming-in-javascript-and-react-part-two-521ea9f57d30) 51 | - [Mastering React Functional Components with Recompose](https://hackernoon.com/mastering-react-functional-components-with-recompose-d4dd6ac98834) 52 | - [Taste the principles of functional programming in React](https://codinglawyer.net/index.php/2018/01/31/taste-the-principles-of-functional-programming-in-react/) 53 | - [The functional side of React](https://medium.com/@andrea.chiarelli/the-functional-side-of-react-229bdb26d9a6) 54 | - [Functional React](https://levelup.gitconnected.com/functional-react-is-it-possible-ceaf5ed91bfd) 55 | 56 | ## With Redux 57 | 58 | - [10 Tips for Better Redux Architecture](https://medium.com/javascript-scene/10-tips-for-better-redux-architecture-69250425af44) 59 | 60 | ## Courses 61 | 62 | - [Functional Programming Patterns With RamdaJS!](https://www.educative.io/collection/5070627052453888/5738600293466112) 63 | - [Professor Frisby Introduces Composable Functional JavaScript](https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript) 64 | - [Introduction to The Beginner's Guide to ReactJS](https://egghead.io/lessons/react-introduction-to-the-beginner-s-guide-to-reactjs) 65 | 66 | ## Books 67 | 68 | - [Professor Frisby's Mostly Adequate Guide to Functional Programming (NEW)](https://mostly-adequate.gitbooks.io/mostly-adequate-guide/content/) 69 | - [Professor Frisby's Mostly Adequate Guide to Functional Programming (OLD)](https://drboolean.gitbooks.io/mostly-adequate-guide/) 70 | - [Functional JavaScript Mini Book by Jichao Ouyang](https://jcouyang.gitbooks.io/functional-javascript/content/en/index.html) 71 | - [Pragmatic Function Javascript online book](https://haskellcamargo.gitbooks.io/pragmatic-functional-javascript/) 72 | 73 | ## Lists 74 | 75 | - [Functional Programming Resources In JavaScript](https://github.com/busypeoples/functional-programming-javascript) 76 | - [Awesome FRP JS](https://github.com/stoeffel/awesome-frp-js) 77 | 78 | 79 | -------------------------------------------------------------------------------- /javascript/books/composing_software/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Composing Software 4 | 5 | ## Composing Software: An Introduction 6 | 7 | [Source Code - Composing Functions](https://github.com/leandrotk/functional-programming-learning-path/blob/master/javascript/composing_software/composing_functions.js) 8 | 9 | 10 | -------------------------------------------------------------------------------- /javascript/books/composing_software/composing_functions.js: -------------------------------------------------------------------------------- 1 | const log = input => console.log(input); 2 | 3 | // Function composition is the process of applying a function to the output of another function. 4 | const g = n => n + 1; 5 | const f = n => n * 2; 6 | 7 | const doStuff = x => { 8 | const gOutput = g(x); 9 | const fOutput = f(gOutput); 10 | return fOutput; 11 | }; 12 | 13 | let result = doStuff(20); 14 | log(result); // 42 15 | 16 | // A different (better) way to do composition 17 | const doStuffBetter = x => f(g(x)); 18 | 19 | result = doStuffBetter(20); 20 | log(result); // 42 21 | 22 | // debugging the doStuff function 23 | const doStuffWithDebugging = x => { 24 | const gOutput = g(x); 25 | console.log(`after g: ${gOutput}`); 26 | const fOutput = f(gOutput); 27 | console.log(`after f: ${fOutput}`); 28 | return fOutput; 29 | }; 30 | 31 | doStuffWithDebugging(20); 32 | // after g: 21 33 | // after f: 42 34 | 35 | // debugging the doStuffBetter function 36 | const compose = (...fns) => n => fns.reduceRight((acc, fn) => fn(acc), n); 37 | 38 | const trace = message => input => { 39 | console.log(`${message} ${input}`); 40 | return input; 41 | }; 42 | 43 | const doStuffBetterWithDebugging = compose( 44 | trace("after f:"), 45 | f, 46 | trace("after g:"), 47 | g 48 | ); 49 | 50 | doStuffBetterWithDebugging(20); 51 | // after g: 21 52 | // after f: 42 53 | 54 | // If you’re chaining, you’re composing. 55 | const list = [1, 2, 3, 4, 5]; 56 | 57 | const sumEvenNumbers = list => { 58 | return list 59 | .filter(n => n % 2 == 0) 60 | .map(n => n * 2) 61 | .reduce((previous, current) => previous + current); 62 | }; 63 | 64 | log(sumEvenNumbers(list)); // 12 65 | -------------------------------------------------------------------------------- /javascript/books/composing_software/declarative_programming.js: -------------------------------------------------------------------------------- 1 | // imperative programming: coding every step of the process 2 | const doubleMap = numbers => { 3 | const doubled = []; 4 | 5 | for (let i = 0; i < numbers.length; i++) { 6 | doubled.push(numbers[i] * 2); 7 | } 8 | 9 | return doubled; 10 | }; 11 | 12 | doubled.push(numbers[i] * 2); 13 | console.log(doubleMap([2, 3, 4])); // [4,6,8] 14 | 15 | // declarative programming: describing the data flow 16 | const doubleMap = numbers => numbers.map(n => n * 2); 17 | doubleMap([2, 3, 4]); // [4,6,8] 18 | 19 | // Declarative code relies more on expressions. An expression is a piece of code which evaluates to some value. 20 | // Examples of expressions: 21 | 22 | 2 * 2; 23 | doubleMap([2, 3, 4]); 24 | Math.max(4, 3, 2); 25 | "a" + "b" + "c"; 26 | -------------------------------------------------------------------------------- /javascript/books/composing_software/functors.js: -------------------------------------------------------------------------------- 1 | // When you see the word functor, you should think “mappable”. 2 | 3 | const double = n => n * 2; 4 | const doubleMap = numbers => numbers.map(double); 5 | doubleMap([1, 2, 3]); // [2, 4, 6] 6 | 7 | const doublePoints = x => x.points * 2; 8 | const doublePointsMap = numbers => numbers.map(doublePoints); 9 | doublePointsMap([ 10 | { name: "ball", points: 2 }, 11 | { name: "coin", points: 3 }, 12 | { name: "candy", points: 4 } 13 | ]); 14 | // [4, 6, 8] 15 | -------------------------------------------------------------------------------- /javascript/books/composing_software/intro_to_js.js: -------------------------------------------------------------------------------- 1 | // const instead of let and var most of the time 2 | const number = 1; 3 | 4 | const arr = [1, 2, 3]; 5 | 6 | // `const obj = { a: a }` but we have a better way to do it 7 | const a = "a"; 8 | const objA = { a }; 9 | 10 | const b = "b"; 11 | const objB = { b }; 12 | 13 | // composing objects with object spread operator 14 | const ab = { ...objA, ...objB }; // { a: 'a', b: 'b' } 15 | 16 | // Destructuring arrays 17 | const [a, b] = ["a", "b"]; 18 | a; // 'a' 19 | b; // 'b' 20 | 21 | // destructuring objects 22 | const { one } = { one: 1 }; 23 | one; // 1 24 | 25 | // but also do multiple destructuring 26 | const action = { type: "SUM", data: 1 }; 27 | const { type, data } = action; 28 | 29 | // we can use this technique in reducers 30 | const reducer = (state = 0, action = {}) => { 31 | const { type, data } = action; 32 | 33 | switch (type) { 34 | case "SUM": 35 | return state + data; 36 | default: 37 | return state; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /javascript/books/mostly_adequate_guide_to_functional_programming/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Mostly Adequate Guide to Functional Programming 4 | 5 | ## Chapter 02 - First Class Functions 6 | 7 | [Source Code - First Class Functions](https://github.com/tk-learning-center/functional-programming-learning-path/blob/master/javascript/mostly_adequate_guide_to_functional_programming/ch02.js) 8 | 9 | 10 | -------------------------------------------------------------------------------- /javascript/books/mostly_adequate_guide_to_functional_programming/ch02.js: -------------------------------------------------------------------------------- 1 | // Chapter 02: First Class Functions 2 | 3 | const hi = name => `Hi ${name}`; 4 | 5 | // const greeting = name => hi(name); 6 | // this is totally redundant, 7 | // because we can treat the greeting function as a value 8 | // and assign this value to the new greeting function, like that: 9 | 10 | const greeting = hi; 11 | 12 | // and use it normal function 13 | greeting('TK'); // Hi TK 14 | 15 | // Another more complex example 16 | // This function `const getServerStuff = callback => ajaxCall(json => callback(json));` is the same as this: 17 | const getServerStuff = ajaxCall; 18 | 19 | // Simplifying this function: 20 | // 1. const getServerStuff = callback => ajaxCall(json => callback(json)); 21 | // 2. const getServerStuff = callback => ajaxCall(callback); 22 | // 3 const getServerStuff = ajaxCall; 23 | 24 | // Treating functions as values (first class), it easier to maintain. 25 | // If we have a wrapped function and it needs to change, we need to change both the wrapped function and the call 26 | 27 | // We have this httpGet function 28 | httpGet('/post/2', json => renderPost(json)); 29 | 30 | // But we need to change the renderPost function to receive not only the json, but also the error (err) 31 | // We change the renderPost function and the calling 32 | httpGet('/post/2', json, err => renderPost(json, err)); 33 | 34 | // Another approach is to treat functions as values and return the renderPost function 35 | // This way we only need to change the renderPost function. The httpGet function stays the same 36 | httpGet('/post/2', renderPost); 37 | -------------------------------------------------------------------------------- /javascript/books/mostly_adequate_guide_to_functional_programming/ch03.js: -------------------------------------------------------------------------------- 1 | // Chapter 03: Pure Happiness with Pure Functions 2 | 3 | const log = input => console.log(input); 4 | 5 | // impure 6 | let minimum = 21; 7 | const impureCheckAge = age => age >= minimum; 8 | 9 | log(impureCheckAge(21)); // true 10 | minimum = 22; 11 | log(impureCheckAge(21)); // false 12 | 13 | // pure 14 | const checkAge = age => age >= 21; 15 | 16 | log(impureCheckAge(21)); // true 17 | log(impureCheckAge(21)); // true 18 | -------------------------------------------------------------------------------- /javascript/books/mostly_adequate_guide_to_functional_programming/ch04.js: -------------------------------------------------------------------------------- 1 | // Chapter 04: Currying 2 | 3 | const log = (input) => console.log(input); 4 | 5 | // The add function will return a function expecting the Y parameter, 6 | // but also remembering the X value via closure 7 | const add = x => y => x + y; 8 | const increment = add(1); 9 | const addTen = add(10); 10 | 11 | log(increment(2)); // 3 12 | log(addTen(2)); // 12 13 | 14 | // Curry implementation 15 | const curry = f => { 16 | const fn = (...args) => { 17 | return f.length == args.length ? f(...args) : (...newArgs) => fn(...args, ...newArgs); 18 | } 19 | 20 | return fn; 21 | } 22 | 23 | const f = (x, y, z) => { return x + y + z }; 24 | 25 | let curriedAdd = curry(f); // function to curry 26 | let add1 = curriedAdd(1); //curried function with x = 1 27 | let add3 = add1(2); // fn 28 | 29 | log(add3(7)); // 10 30 | log(add1(2, 7)); // 10 31 | 32 | // Exercises 33 | const split = (separator, string) => string.split(separator); 34 | log(split(' ', 'a bunch of words')); // [ 'a', 'bunch', 'of', 'words' ] 35 | 36 | const curriedSplit = curry(split); 37 | 38 | const spaceSplit = curriedSplit(' '); 39 | log(spaceSplit('a bunch of words')); // [ 'a', 'bunch', 'of', 'words' ] 40 | 41 | const hifenSplit = curriedSplit('-'); 42 | log(hifenSplit('a-bunch-of-words')); // [ 'a', 'bunch', 'of', 'words' ] 43 | -------------------------------------------------------------------------------- /javascript/closure.js: -------------------------------------------------------------------------------- 1 | const log = (...args) => console.log(...args); 2 | 3 | const posts = [ 4 | { id: '0001', title: 'Title 0001' }, 5 | { id: '0002', title: 'Title 0002' }, 6 | { id: '0003', title: 'Title 0003' }, 7 | { id: '0004', title: 'Title 0004' } 8 | ] 9 | 10 | const findIn = (list = []) => ({ 11 | where: (field) => ({ 12 | isEqualTo: (value) => { 13 | return list.find(el => el[field] === value); 14 | } 15 | }) 16 | }); 17 | 18 | // the field is fixed in the isEqualTo function scope 19 | // so it has access to the value 20 | 21 | log( 22 | findIn(posts) 23 | .where('id') 24 | .isEqualTo('0001') 25 | ); 26 | -------------------------------------------------------------------------------- /javascript/currying.js: -------------------------------------------------------------------------------- 1 | const log = (...args) => console.log(...args); 2 | 3 | const add = (x) => (y) => x + y; 4 | 5 | /*** 6 | const add = (x) => { 7 | return (y) => { 8 | Fix x = ? 9 | x + y; 10 | } 11 | } 12 | ***/ 13 | 14 | const increment = add(1); 15 | 16 | let one = 1; 17 | let two = increment(one); 18 | let three = increment(two); 19 | 20 | log(two); // 2 21 | log(three); // 3 22 | 23 | const addTen = add(10); 24 | 25 | log(addTen(10)); // 20 26 | log(addTen(0)); // 10 27 | 28 | // --------------------------------------------------------------------------------------------- 29 | 30 | // Outside of function composition, currying is a useful abstraction we can use to specialize functions 31 | // One example is to curry the map function 32 | 33 | const map = fn => mappable => mappable.map(fn); 34 | 35 | const arr = [1, 2, 3, 4, 5]; 36 | const isEven = n => n % 2 === 0; 37 | 38 | const stripe = n => isEven(n) ? 'dark' : 'light'; 39 | const stripeAll = map(stripe); 40 | const striped = stripeAll(arr); 41 | log(striped); // => ['light', 'dark', 'light', 'dark', 'light'] 42 | 43 | const double = n => n * 2; 44 | const doubleAll = map(double); 45 | const doubled = doubleAll(arr); 46 | log(doubled); // => [2, 4, 6, 8, 10] 47 | 48 | // Get element by value from list of objects 49 | // Using currying for specialized functions 50 | 51 | const posts = [ 52 | { id: '0001', title: 'Title 0001' }, 53 | { id: '0002', title: 'Title 0002' }, 54 | { id: '0003', title: 'Title 0003' }, 55 | { id: '0004', title: 'Title 0004' } 56 | ] 57 | 58 | const getFromBasic = (list, field) => (value) => 59 | list[list.map(el => el[field]).indexOf(value)]; 60 | 61 | const getByIdBasic = (list, field = "id") => getFromBasic(list, field); 62 | 63 | let selected = getByIdBasic(posts)('0003'); 64 | log(selected); 65 | 66 | const getFrom = (field) => (list) => (value) => 67 | list[list.map(el => el[field]).indexOf(value)]; 68 | 69 | const getById = getFrom('id'); 70 | const getByTitle = getFrom('title'); 71 | 72 | selected = getById(posts)('0003'); 73 | log(selected); 74 | selected = getByTitle(posts)('Title 0004'); 75 | log(selected); 76 | 77 | // --------------------------------------------------------------------------------------------- 78 | 79 | /* 80 | jQuery approach 81 | $('some-css-class').on('click', callback); 82 | */ 83 | 84 | /* 85 | How I want to use 86 | - onClick(element, handler); 87 | - onHover(element, handler); 88 | */ 89 | 90 | /* 91 | A more generic approach 92 | (event) => (element, handler) => fn 93 | 94 | The idea is to use curry 95 | - receive the event string first and return a new function 96 | - the new function receives the element and the callback handler 97 | - passing the event string first helps to create specialized functions (e.g. onClick and onHover) 98 | */ 99 | const eventListener = (event) => (element, handler) => element.addEventListener(event, handler); 100 | 101 | const onClick = eventListener('click'); 102 | const onHover = eventListener('hover'); 103 | 104 | /* 105 | Example: on click event for the vote button 106 | This example runs page this StackOverflow page 107 | https://stackoverflow.com/questions/6348494/addeventlistener-vs-onclick 108 | */ 109 | const voteUpButton = document.getElementsByClassName('js-vote-up-btn')[0]; 110 | const helloAlert = () => alert('Hello!'); 111 | 112 | onClick(voteUpButton, helloAlert); 113 | -------------------------------------------------------------------------------- /javascript/first_class_citizens.js: -------------------------------------------------------------------------------- 1 | /* 2 | Functions as first class citizens: Treats functions as values 3 | - Refer to it from constants and variables 4 | - Pass it as a parameter to other functions 5 | - Return it as result from other functions 6 | */ 7 | -------------------------------------------------------------------------------- /javascript/function_as_value.js: -------------------------------------------------------------------------------- 1 | const sum = (a, b) => a + b; 2 | const subtraction = (a, b) => a - b; 3 | 4 | const doubleSum = (a, b) => sum(a, b) * 2; 5 | const doubleSubtraction = (a, b) => subtraction(a, b) * 2; 6 | 7 | const doubleOperator = (f, a, b) => f(a, b) * 2; 8 | 9 | doubleOperator(sum, 1, 1); 10 | doubleOperator(subtraction, 3, 1); 11 | 12 | const doubleOperator = (f) => (a, b) => f(a, b) * 2; 13 | 14 | const doubleSum = doubleOperator(sum); 15 | const doubleSubtraction = doubleOperator(subtraction); 16 | 17 | doubleSum(1, 1); 18 | doubleSubtraction(3, 1); -------------------------------------------------------------------------------- /javascript/function_composition.js: -------------------------------------------------------------------------------- 1 | const log = (...args) => console.log(...args); 2 | 3 | /* 4 | Function Composition combines two or more functions together 5 | To perform function composition, 6 | you simply have the result of each function be passed as the argument to the next 7 | 8 | As an example we'll implement a simple function that calculates total purchase price 9 | by taking the purchase price, applying an 8% tax, and adding $10 (shipping and handling) 10 | */ 11 | 12 | const calculateTotalBasic = (amount) => { 13 | return (amount * 1.08) + 10; 14 | } 15 | 16 | /* 17 | Now let's refactor it: 18 | - implement applyTax function 19 | - implement applyShippingAndHandling 20 | - compose those functions into the calculate function 21 | */ 22 | 23 | const applyTax = (amount) => amount * 1.08; 24 | 25 | const applyShippingAndHandling = (amount) => amount + 10; 26 | 27 | const calculateTotal = (amount) => { 28 | return applyShippingAndHandling(applyTax(amount)); 29 | } 30 | 31 | // compose function using reduce 32 | const compose = (...fns) => (x) => { 33 | return fns.reduceRight((composedFns, fn) => fn(composedFns), x) 34 | }; 35 | 36 | const shoutBasic = (str) => `${str.toUpperCase()}!`; 37 | 38 | log(shoutBasic('something')); 39 | log(shoutBasic('something else')); 40 | log(shoutBasic('nothing')); 41 | 42 | // compose toUpperCase and exclaim functions 43 | const toUpperCase = (str) => str.toUpperCase(); 44 | const exclaim = (str) => `${str}!`; 45 | const shout = compose(exclaim, toUpperCase); 46 | 47 | log(shout('something')); 48 | log(shout('something else')); 49 | log(shout('nothing')); 50 | -------------------------------------------------------------------------------- /javascript/high_order_functions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Higher-order functions are functions that work on other functions 3 | Meaning that they can take one or more functions as an argument and 4 | can also return a function as a result 5 | */ 6 | 7 | /* 8 | Imagine you have this element in the HTML: 9 | 10 | 11 | Let's add a click event listener to the button 12 | */ 13 | 14 | document.getElementById("btn").addEventListener("click", () => { 15 | console.log("You clicked me!"); 16 | }); 17 | 18 | /* We can also extract the logger code in a function to be explicit */ 19 | 20 | const logger = (message) => () => { console.log(message); }; 21 | const clickLogger = logger('You clicked me'); 22 | 23 | document.getElementById('btn').addEventListener('click', clickLogger); 24 | 25 | /* addEventListener is a high order function */ 26 | -------------------------------------------------------------------------------- /javascript/immutability/avoid_array_mutability.js: -------------------------------------------------------------------------------- 1 | // fill 2 | var ar = [1, 2, 3, 4] 3 | ar.fill(0, 2, 4) // (4) [1, 2, 0, 0] 4 | ar // (4) [1, 2, 0, 0] 5 | 6 | // pop 7 | var ar = [1, 2, 3, 4] 8 | ar.pop() // 4 9 | ar // (3) [1, 2, 3] 10 | 11 | // push 12 | var ar = [1, 2, 3, 4] 13 | ar.push(5) // 5 14 | ar // (5) [1, 2, 3, 4, 5] 15 | 16 | // reverse 17 | var ar = [1, 2, 3, 4] 18 | ar.reverse() // (4) [4, 3, 2, 1] 19 | ar // (4) [4, 3, 2, 1] 20 | 21 | // shift 22 | var ar = [1, 2, 3, 4] 23 | ar.shift() // 1 24 | ar // (3) [2, 3, 4] 25 | 26 | // sort 27 | var ar = [1, 4, 3, 2] 28 | ar.sort() // (4) [1, 2, 3, 4] 29 | ar // (4) [1, 2, 3, 4] 30 | 31 | // splice 32 | var ar = [1, 2, 3, 5] 33 | ar.splice(3, 0, 4) // [] 34 | ar // (5) [1, 2, 3, 4, 5] 35 | 36 | // unshift 37 | var ar = [3, 4] 38 | ar.unshift(1, 2) // 4 39 | ar // (4) [1, 2, 3, 4] 40 | -------------------------------------------------------------------------------- /javascript/immutability/immutability.js: -------------------------------------------------------------------------------- 1 | /* Strings are immutable */ 2 | var name = 'TK'; 3 | name[0] = 'D'; 4 | console.log(name); // 'TK' 5 | 6 | /* 7 | immutable data is important because we need to be able to attach dependable, unchanging values to our functions 8 | 9 | In multi-threaded applications that is a great thing. 10 | It allows for a thread to act on data represented by immutable objects 11 | without worrying what other threads are up to. 12 | 13 | immutable objects are more thread-safe than mutable objects. 14 | */ 15 | 16 | // When creating a "constant", we can't reference another value to it. 17 | const reference = 1; 18 | // reference = 2; => TypeError: Assignment to constant variable. 19 | 20 | // We can create another array by using array destructuring 21 | const array = [1, 2]; 22 | 23 | const newArray = [...array, 3]; 24 | 25 | console.log(newArray); 26 | 27 | // We can create another object by using object destructuring 28 | const object = { 29 | one: 1, 30 | two: 2 31 | }; 32 | 33 | const newObject = { ...object, three: 3 }; 34 | 35 | console.log(newObject); 36 | -------------------------------------------------------------------------------- /javascript/immutability/slugify.js: -------------------------------------------------------------------------------- 1 | const urlWithMutation = ' I will be a url slug '; 2 | 3 | const slugifyWithMutation = (url) => { 4 | url = url.toLowerCase(); 5 | url = url.trim(); 6 | url = url.split(' '); 7 | url = url.join('-'); 8 | return url; 9 | } 10 | 11 | slugifyWithMutation(urlWithMutation); // i-will-be-a-url-slug 12 | 13 | const url = ' I will be a url slug '; 14 | 15 | const slugify = (url) => 16 | url 17 | .toLowerCase() 18 | .trim() 19 | .split(' ') 20 | .join('-'); 21 | 22 | slugify(url); // i-will-be-a-url-slug 23 | -------------------------------------------------------------------------------- /javascript/lazy.js: -------------------------------------------------------------------------------- 1 | const sum = (a, b) => a + b; 2 | 3 | const result = sum(1 + 2, 3); 4 | console.log(result); 5 | 6 | const lazySum = (a, b) => () => a() + b(); 7 | 8 | const lazyResult = lazySum(() => 1 + 2, () => 3)(); 9 | console.log(lazyResult); 10 | -------------------------------------------------------------------------------- /javascript/partial_application.js: -------------------------------------------------------------------------------- 1 | /* 2 | Partial application is a way to turn a function that expects multiple parameters 3 | into one that will keep returning a new function until it receives all its arguments 4 | 5 | "partially apply" some of the arguments now, filling in the rest later. 6 | 7 | Partial application allows us to partially apply certain argument to create 8 | new functions out of existing ones. 9 | */ 10 | 11 | const calculateTotal = (amount) => { 12 | return (amount * 1.08) + 10; 13 | } 14 | 15 | const R = require('ramda'); 16 | const applyTaxOfEightPercent = R.partial(applyTax, [0.08]); 17 | 18 | applyTaxOfEightPercent(100); // 108 19 | applyTaxOfEightPercent(200); // 216 20 | applyTaxOfEightPercent(190); // 205.2 21 | applyTaxOfEightPercent(10000); // 10800 22 | -------------------------------------------------------------------------------- /javascript/purity_part_1.js: -------------------------------------------------------------------------------- 1 | /* 2 | There are two qualities that make a function "pure": 3 | - The function depends only on the input provided to it to produce a result (and not on any external state). 4 | - The function does not cause any observable side effects, such as modifying a global object or modifying a parameter passed by reference. 5 | */ 6 | 7 | const PI = 3.14; 8 | 9 | /* Not pure: it uses the global constant */ 10 | const calculateArea = (radius) => radius * radius * PI; 11 | 12 | /* Pure: it uses only parameters passed to the function */ 13 | const calculateArea = (radius, PI) => radius * radius * PI; 14 | 15 | /* ------------------------------------------------------ */ 16 | 17 | let count = 1; 18 | 19 | /* Not pure: it uses the global variable and modify the variable */ 20 | const increaseCount = (value) => count = count + value; 21 | 22 | /* ------------------------------------------------------ */ 23 | 24 | /* Not pure: it modifies the array - the reverse method reverses the array in place */ 25 | const reverseArray = (array) => array.reverse(); 26 | 27 | /* ------------------------------------------------------ */ 28 | 29 | /* Not pure: make call to an external API */ 30 | async function amountExceedsBuyLimit(amount) { 31 | const limit = await getBuyLimits(); /* assume API call */ 32 | return amount > limit; 33 | } 34 | 35 | /* Pure */ 36 | async function amountExceedsBuyLimit(amount, limit) { 37 | return amount > limit; 38 | } 39 | -------------------------------------------------------------------------------- /javascript/purity_part_2.js: -------------------------------------------------------------------------------- 1 | /* Benefit 1: Pure functions are predictable */ 2 | 3 | const PI = 3.14; 4 | const calculateArea = (radius) => radius * radius * PI; 5 | 6 | /* 7 | This impure function is reliant on the global variable PI to make the calculation 8 | The PI is a global variable, so anyone can update it, and automatically change the result of calculateArea function 9 | Inpure functions are unpredictable 10 | */ 11 | 12 | /* ------------------------------------------------------ */ 13 | 14 | /* Benefit 2: Pure functions are easy to test */ 15 | 16 | /* Imagine test this impure function */ 17 | async function amountExceedsBuyLimit(amount) { 18 | const limit = await getBuyLimits(); /* assume API call */ 19 | return amount > limit; 20 | } 21 | 22 | /* We need to mock the API call to test our function */ 23 | describe('amountExceedsBuyLimit', () => { 24 | let scope, limits; 25 | 26 | /* Mock API call */ 27 | before(() => { 28 | scope = nock('https://myApi.com'); 29 | scope 30 | .get('/buyLimit') 31 | .matchHeader('Content-Type', 'application/json') 32 | .reply(200, { 33 | buyLimit: 5000, 34 | }); 35 | }); 36 | 37 | /* Test the function */ 38 | it('is false', () => { 39 | const amountExceedsLimit = amountExceedsBuyLimit(200); 40 | expect(amountExceedsLimit).to.be.false(); 41 | }); 42 | 43 | it('is true', () => { 44 | const amountExceedsLimit = amountExceedsBuyLimit(10000); 45 | expect(amountExceedsLimit).to.be.true(); 46 | }); 47 | }); 48 | 49 | /* Now imagine test this pure function */ 50 | async function amountExceedsBuyLimit(amount, limit) { 51 | return amount > limit; 52 | } 53 | 54 | /* Pretty simple */ 55 | describe('amountExceedsBuyLimit', () => { 56 | it('is false', () => { 57 | const amountExceedsLimit = amountExceedsBuyLimit(200, 5000); 58 | expect(amountExceedsLimit).to.be.false(); 59 | }); 60 | 61 | it('is true', () => { 62 | const amountExceedsLimit = amountExceedsBuyLimit(10000, 5000); 63 | expect(amountExceedsLimit).to.be.true(); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /javascript/reduce.js: -------------------------------------------------------------------------------- 1 | const log = (...args) => console.log(...args); 2 | 3 | const arr = [1, 2, 3, 4, 5]; 4 | 5 | // Building a sum function with reduce 6 | const sumReducer = (acc, value) => acc + value; 7 | 8 | log('Sum with Reduce'); 9 | let total = arr.reduce(sumReducer, 0); 10 | log(total); // 15 11 | log(); 12 | 13 | /* -------------------------------------- */ 14 | 15 | // Building map function with reduce 16 | // API: map(fn, arr); 17 | // fn => function that will process each element in the collection 18 | // arr => the collection to be processed 19 | // [1, 2, 3, 4, 5] => fn => [2, 4, 6, 8, 10] 20 | 21 | const map = (fn, arr) => arr.reduce((acc, value) => { 22 | return acc.concat(fn(value)); 23 | }, []); 24 | 25 | const timesTwo = value => value * 2; 26 | const increment = value => value + 1; 27 | const isEven = value => value % 2 === 0; 28 | 29 | let timesTwoMapping = map(timesTwo, arr); 30 | let incrementMapping = map(increment, arr); 31 | let isEvenMapping = map(isEven, arr); 32 | 33 | log('Map with Reduce'); 34 | log(timesTwoMapping); // [2, 4, 6, 8, 10] 35 | log(incrementMapping); // [2, 3, 4, 5, 6] 36 | log(isEvenMapping); // [false, true, false, true, false] 37 | log(); 38 | 39 | /* -------------------------------------- */ 40 | 41 | // Building a filter function with reduce 42 | // API: filter(fn, arr); 43 | // fn => function that will be used to filter each element of the collection 44 | // arr => the collection to be processed 45 | 46 | const filter = (fn, arr) => arr.reduce((acc, value) => { 47 | return fn(value) ? acc.concat(value) : acc 48 | }, []); 49 | 50 | const moreThan3 = value => value > 3; 51 | 52 | let moreThan3Value = filter(moreThan3, arr); 53 | let evenValues = filter(isEven, arr); 54 | 55 | log('Filter with Reduce'); 56 | log(moreThan3Value); // [4, 5] 57 | log(evenValues); // [2, 4] 58 | log(); 59 | 60 | /* -------------------------------------- */ 61 | 62 | // Building a compose function with reduce 63 | // API: compose(fn1, fn2, fn3, ...) 64 | // fn1: function to be composed 65 | 66 | const compose = (...fns) => x => { 67 | return fns.reduceRight((composedFns, fn) => fn(composedFns), x) 68 | }; 69 | 70 | const f = (x) => x + 1; 71 | const g = (x) => x / 2; 72 | const h = (x) => x * 3; 73 | 74 | const composedFns = compose(f, g, h); 75 | let finalValue = composedFns(2); 76 | 77 | log('Compose with Reduce'); 78 | log(finalValue); // 4 79 | log(); 80 | 81 | /* -------------------------------------- */ 82 | 83 | // Building a pipe function with reduce 84 | // API: pipe(fn1, fn2, fn3, ...) 85 | // fn1: function to be composed 86 | 87 | const pipe = (...fns) => x => fns.reduce((pipedFns, fn) => fn(pipedFns), x); 88 | 89 | const pipedFns = pipe(f, g, h); 90 | finalValue = pipedFns(1); 91 | 92 | log('Pipe with Reduce'); 93 | log(finalValue); // 3 94 | log(); 95 | -------------------------------------------------------------------------------- /javascript/referentially_transparent_function.js: -------------------------------------------------------------------------------- 1 | /* 2 | If a function consistently yields the same result for the same input, 3 | it is referentially transparent. 4 | */ 5 | 6 | const square = (x) => x * x; 7 | 8 | console.log(square(4)) /* 16 */ 9 | console.log(square(4)) /* 16 */ 10 | console.log(square(4)) /* 16 */ 11 | console.log(square(4)) /* 16 */ 12 | 13 | /* 14 | “well, doesn't every function return the same result for the same input?”. 15 | Consider this function that handle a random number 16 | */ 17 | 18 | const getRandomNumber = (max, min) => Math.random() * (max - min) + min; 19 | 20 | getRandomNumber(10, 2) 21 | getRandomNumber(10, 2) 22 | getRandomNumber(10, 2) 23 | 24 | /* 25 | referential transparency gives us the ability to freely replace an expression 26 | with its value and not change the behavior of the program. 27 | 28 | f(4) can be replaced with 16, 29 | g(4) can be replaced with 20, 30 | and the result is not changed. 31 | 32 | f(x) = x * x 33 | f(4) = 16 34 | 35 | g(x) = f(x) + x 36 | g(4) = f(4) + 4 37 | g(4) = 16 + 4 38 | g(4) = 20 39 | 40 | Pure functions + immutable data = referential transparency 41 | 42 | Some benefits: 43 | It makes it much easier to refactor and rewrite programs. 44 | - Since a pure, referentially transparent function can be freely replaced by it’s value, 45 | the only thing we have to worry about when we refactor it is that we get the same 46 | value for a given input. 47 | 48 | - The function doesn’t have any side effects or external dependencies. 49 | This lets us focus on refactoring the single function without having 50 | to worry about all the baggage associated with the function in the outside world. 51 | */ 52 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem01.clj: -------------------------------------------------------------------------------- 1 | ; http://www.4clojure.com/problem/1 2 | (= true true) 3 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem02.clj: -------------------------------------------------------------------------------- 1 | ; http://www.4clojure.com/problem/2 2 | (= (- 10 (* 2 3)) 4) 3 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem03.clj: -------------------------------------------------------------------------------- 1 | ; http://www.4clojure.com/problem/3#prob-title 2 | (= "HELLO WORLD" (.toUpperCase "hello world")) 3 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem04.clj: -------------------------------------------------------------------------------- 1 | ;; http://www.4clojure.com/problem/4 2 | 3 | (= (list :a :b :c) '(:a :b :c)) 4 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem05.clj: -------------------------------------------------------------------------------- 1 | ;; http://www.4clojure.com/problem/5#prob-title 2 | 3 | (= '(1 2 3 4) (conj '(2 3 4) 1)) 4 | (= '(1 2 3 4) (conj '(3 4) 2 1)) 5 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem06.clj: -------------------------------------------------------------------------------- 1 | ;; http://www.4clojure.com/problem/6 2 | 3 | (= [:a :b :c] (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c)) 4 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem07.clj: -------------------------------------------------------------------------------- 1 | ;; http://www.4clojure.com/problem/7 2 | 3 | (= [1 2 3 4] (conj [1 2 3] 4)) 4 | (= [1 2 3 4] (conj [1 2] 3 4)) 5 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem19.clj: -------------------------------------------------------------------------------- 1 | ; http://www.4clojure.com/problem/19 2 | 3 | ; Solution 1 4 | (fn [coll] 5 | (loop [item (first coll) 6 | coll coll] 7 | (if (empty? (rest coll)) 8 | item 9 | (recur (first (rest coll)) (rest coll))))) 10 | 11 | ; Solution 2 12 | (fn [coll] 13 | (first (reverse coll))) 14 | 15 | ; Solution 3 16 | #(first (reverse %)) 17 | 18 | ; Solution 4 19 | (comp first reverse) 20 | 21 | ; Solution 5 22 | (fn [coll] 23 | (-> coll 24 | reverse 25 | first)) 26 | 27 | ; Solution 6 28 | (fn [coll] 29 | (loop [[item & remaining] coll] 30 | (if (empty? remaining) 31 | item 32 | (recur remaining)))) 33 | -------------------------------------------------------------------------------- /programming_challenges/4clojure/problem20.clj: -------------------------------------------------------------------------------- 1 | ; http://www.4clojure.com/problem/20 2 | 3 | (comp second reverse) 4 | -------------------------------------------------------------------------------- /programming_challenges/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Resources 4 | 5 | ## Websites 6 | 7 | - [4Clojure](http://www.4clojure.com/) 8 | - [Clojure Koans](https://github.com/functional-koans/clojure-koans) 9 | - [Exercism Clojure Track](https://exercism.io/my/tracks/clojure) 10 | - [Exercism JavaScript Track](https://exercism.io/my/tracks/javascript) 11 | - [Hacker Rank FP Path](https://www.hackerrank.com/domains/fp) 12 | - [Clojure Katas](https://github.com/marshallshen/clojure-katas) 13 | - [Wonderland Clojure Katas](https://github.com/gigasquid/wonderland-clojure-katas) 14 | 15 | ## Blogs 16 | 17 | - [Acing Nubank’s technical exercise — part 1](https://medium.com/building-nubank/acing-nubanks-technical-exercise-part-1-59c8a6d3829d) 18 | - [Acing Nubank’s technical exercise — part 2](https://medium.com/building-nubank/acing-nubanks-technical-exercise-part-2-2366c933977e) 19 | 20 | 21 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/.lein-failures: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/.lein-repl-history: -------------------------------------------------------------------------------- 1 | (defn int->digits [int] 2 | (map (comp #(- % 48) int) (str int))) 3 | (defn power-by-two [digits] 4 | (map #(* % (count digits)) digits)) 5 | (defn powered-sum [num] 6 | (->> num 7 | int->digits 8 | power-by-two 9 | (reduce +))) 10 | (defn armstrong? [num] 11 | (= (powered-sum num) num)) 12 | (armstrong? 123) 13 | (int->digits 123) 14 | quit 15 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/README.md: -------------------------------------------------------------------------------- 1 | # Armstrong Numbers 2 | 3 | An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits. 4 | 5 | For example: 6 | 7 | - 9 is an Armstrong number, because `9 = 9^1 = 9` 8 | - 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1` 9 | - 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` 10 | - 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` 11 | 12 | Write some code to determine whether a number is an Armstrong number. 13 | ## Source 14 | 15 | Wikipedia [https://en.wikipedia.org/wiki/Narcissistic_number](https://en.wikipedia.org/wiki/Narcissistic_number) 16 | 17 | ## Submitting Incomplete Solutions 18 | It's possible to submit an incomplete solution so you can see how others have completed the exercise. 19 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/project.clj: -------------------------------------------------------------------------------- 1 | (defproject armstrong-numbers "0.1.0-SNAPSHOT" 2 | :description "armstrong-numbers exercise" 3 | :url "https://github.com/exercism/clojure/tree/master/exercises/armstrong-numbers" 4 | :dependencies [[org.clojure/clojure "1.10.0"]]) 5 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/src/armstrong_numbers.clj: -------------------------------------------------------------------------------- 1 | (ns armstrong-numbers) 2 | 3 | (defn int->digits [num] 4 | (map (comp #(- % 48) int) (str num))) 5 | 6 | (defn power-by-two [digits digit] 7 | (reduce * (repeat (count digits) digit))) 8 | 9 | (defn power-all-by-two [digits] 10 | (map (partial power-by-two digits) digits)) 11 | 12 | (defn powered-sum [num] 13 | (->> num 14 | int->digits 15 | power-all-by-two 16 | (reduce +))) 17 | 18 | (defn armstrong? [num] 19 | (= (powered-sum num) num)) 20 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/target/classes/META-INF/maven/armstrong-numbers/armstrong-numbers/pom.properties: -------------------------------------------------------------------------------- 1 | #Leiningen 2 | #Thu Jan 31 22:57:53 BRST 2019 3 | groupId=armstrong-numbers 4 | artifactId=armstrong-numbers 5 | version=0.1.0-SNAPSHOT 6 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/target/stale/leiningen.core.classpath.extract-native-dependencies: -------------------------------------------------------------------------------- 1 | [{:dependencies {org.clojure/clojure {:vsn "1.10.0", :native-prefix nil}, org.clojure/spec.alpha {:vsn "0.2.176", :native-prefix nil}, org.clojure/core.specs.alpha {:vsn "0.2.44", :native-prefix nil}, nrepl {:vsn "0.5.3", :native-prefix nil}, nrepl/bencode {:vsn "1.0.0", :native-prefix nil}, clojure-complete {:vsn "0.2.5", :native-prefix nil}}, :native-path "target/native"} {:native-path "target/native", :dependencies {org.clojure/clojure {:vsn "1.10.0", :native-prefix nil, :native? false}, org.clojure/spec.alpha {:vsn "0.2.176", :native-prefix nil, :native? false}, org.clojure/core.specs.alpha {:vsn "0.2.44", :native-prefix nil, :native? false}, nrepl {:vsn "0.5.3", :native-prefix nil, :native? false}, nrepl/bencode {:vsn "1.0.0", :native-prefix nil, :native? false}, clojure-complete {:vsn "0.2.5", :native-prefix nil, :native? false}}}] -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/armstrong-numbers/test/armstrong_numbers_test.clj: -------------------------------------------------------------------------------- 1 | (ns armstrong-numbers-test 2 | (:require [clojure.test :refer [deftest is testing]] 3 | [armstrong-numbers :refer [armstrong?]])) 4 | 5 | (deftest armstrong-number-5 6 | (testing "Single digit numbers are Armstrong numbers" 7 | (is (armstrong? 5)))) 8 | 9 | (deftest not-armstrong-number-10 10 | (testing "There are no 2 digit Armstrong numbers" 11 | (is (not (armstrong? 10))))) 12 | 13 | (deftest armstrong-number-153 14 | (testing "Three digit number that is an Armstrong number" 15 | (is (armstrong? 153)))) 16 | 17 | (deftest not-armstrong-number-100 18 | (testing "Three digit number that is not an Armstrong number" 19 | (is (not (armstrong? 100))))) 20 | 21 | (deftest armstrong-number-9474 22 | (testing "Four digit number that is an Armstrong number" 23 | (is (armstrong? 9474)))) 24 | 25 | (deftest not-armstrong-number-9475 26 | (testing "Four digit number that is not an Armstrong number" 27 | (is (not (armstrong? 9476))))) 28 | 29 | (deftest armstrong-number-9926315 30 | (testing "Seven digit number that is an Armstrong number" 31 | (is (armstrong? 9926315)))) 32 | 33 | (deftest not-armstrong-number-9926314 34 | (testing "Seven digit number that is not an Armstrong number" 35 | (is (not (armstrong? 9926314))))) 36 | 37 | (deftest armstrong-number-21897142587612075 38 | (testing "Seventeen digit number that is an Armstrong number" 39 | (is (armstrong? 21897142587612075)))) 40 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/hello-world/README.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 | The classical introductory exercise. Just say "Hello, World!". 4 | 5 | ["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is 6 | the traditional first program for beginning programming in a new language 7 | or environment. 8 | 9 | The objectives are simple: 10 | 11 | - Write a function that returns the string "Hello, World!". 12 | - Run the test suite and make sure that it succeeds. 13 | - Submit your solution and check it at the website. 14 | 15 | If everything goes well, you will be ready to fetch your first real exercise. 16 | 17 | ### Project Structure 18 | 19 | Clojure exercises in exercism use [leiningen](http://leiningen.org/) to configure and run your code 20 | and use [leiningen standard directory structure](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#directory-layout). 21 | 22 | You will find a test file named `hello_world_test.clj` inside `test` directory. 23 | Write your code in `src/hello_world.clj`. It should use the namespace `hello-world` so that tests can pick it up. 24 | 25 | ### Running tests 26 | 27 | Run the tests using `lein test` command and make them pass: 28 | 29 | ``` 30 | $ lein test 31 | 32 | lein test hello-world-test 33 | 34 | Ran 1 tests containing 1 assertions. 35 | 0 failures, 0 errors. 36 | ``` 37 | 38 | Then submit the exercise using: 39 | 40 | ``` 41 | $ exercism submit src/hello_world.clj 42 | ``` 43 | 44 | For more detailed instructions and learning resources refer [exercism's clojure language page](http://exercism.io/languages/clojure). 45 | 46 | ## Source 47 | 48 | This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) 49 | 50 | ## Submitting Incomplete Solutions 51 | It's possible to submit an incomplete solution so you can see how others have completed the exercise. 52 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/hello-world/project.clj: -------------------------------------------------------------------------------- 1 | (defproject hello-world "0.1.0-SNAPSHOT" 2 | :description "hello-world exercise." 3 | :url "https://github.com/exercism/clojure/tree/master/exercises/hello-world" 4 | :dependencies [[org.clojure/clojure "1.9.0"]]) 5 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/hello-world/src/hello-world.clj: -------------------------------------------------------------------------------- 1 | (ns hello-world) 2 | 3 | (defn hello [] "Hello, World!") 4 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/hello-world/test/hello-world-test.clj: -------------------------------------------------------------------------------- 1 | (ns hello-world-test 2 | (:require [clojure.test :refer [deftest is]] 3 | hello-world)) 4 | 5 | (deftest hello-world-test 6 | (is (= "Hello, World!" (hello-world/hello)))) 7 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/.lein-failures: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/.nrepl-port: -------------------------------------------------------------------------------- 1 | 62204 -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/README.md: -------------------------------------------------------------------------------- 1 | # Two Fer 2 | 3 | `Two-fer` or `2-fer` is short for two for one. One for you and one for me. 4 | 5 | Given a name, return a string with the message: 6 | 7 | ```text 8 | One for X, one for me. 9 | ``` 10 | 11 | Where X is the given name. 12 | 13 | However, if the name is missing, return the string: 14 | 15 | ```text 16 | One for you, one for me. 17 | ``` 18 | 19 | Here are some examples: 20 | 21 | |Name | String to return 22 | |:------:|:-----------------: 23 | |Alice | One for Alice, one for me. 24 | |Bob | One for Bob, one for me. 25 | | | One for you, one for me. 26 | |Zaphod | One for Zaphod, one for me. 27 | ## Source 28 | 29 | [https://github.com/exercism/problem-specifications/issues/757](https://github.com/exercism/problem-specifications/issues/757) 30 | 31 | ## Submitting Incomplete Solutions 32 | It's possible to submit an incomplete solution so you can see how others have completed the exercise. 33 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/project.clj: -------------------------------------------------------------------------------- 1 | (defproject two-fer "0.1.0-SNAPSHOT" 2 | :description "two-fer exercise." 3 | :url "https://github.com/exercism/clojure/tree/master/exercises/two-fer" 4 | :dependencies [[org.clojure/clojure "1.8.0"]]) 5 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/src/two_fer.clj: -------------------------------------------------------------------------------- 1 | (ns two-fer) 2 | 3 | (defn two-fer 4 | ([] "One for you, one for me.") 5 | ([name] (str "One for " name ", one for me."))) 6 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/target/classes/META-INF/maven/two-fer/two-fer/pom.properties: -------------------------------------------------------------------------------- 1 | #Leiningen 2 | #Sun Feb 03 05:19:15 BRST 2019 3 | groupId=two-fer 4 | artifactId=two-fer 5 | version=0.1.0-SNAPSHOT 6 | -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/target/repl-port: -------------------------------------------------------------------------------- 1 | 62204 -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/target/stale/leiningen.core.classpath.extract-native-dependencies: -------------------------------------------------------------------------------- 1 | [{:dependencies {org.clojure/clojure {:vsn "1.8.0", :native-prefix nil}, nrepl {:vsn "0.5.3", :native-prefix nil}, nrepl/bencode {:vsn "1.0.0", :native-prefix nil}, clojure-complete {:vsn "0.2.5", :native-prefix nil}}, :native-path "target/native"} {:native-path "target/native", :dependencies {org.clojure/clojure {:vsn "1.8.0", :native-prefix nil, :native? false}, clojure-complete {:vsn "0.2.5", :native-prefix nil, :native? false}, nrepl {:vsn "0.5.3", :native-prefix nil, :native? false}, nrepl/bencode {:vsn "1.0.0", :native-prefix nil, :native? false}}}] -------------------------------------------------------------------------------- /programming_challenges/exercism/clojure/two-fer/test/two_fer_test.clj: -------------------------------------------------------------------------------- 1 | (ns two-fer-test 2 | (:require [clojure.test :refer [deftest is]] 3 | two-fer)) 4 | 5 | (deftest two-fer-test 6 | (is (= "One for you, one for me." (two-fer/two-fer)))) 7 | 8 | (deftest name-alice-test 9 | (is (= "One for Alice, one for me." (two-fer/two-fer "Alice")))) 10 | 11 | (deftest name-bob-test 12 | (is (= "One for Bob, one for me." (two-fer/two-fer "Bob")))) 13 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/collatz-conjecture.js: -------------------------------------------------------------------------------- 1 | export const steps = n => { 2 | if (n <= 0) throw "Only positive numbers are allowed"; 3 | 4 | let times = 0; 5 | 6 | while (n !== 1) { 7 | if (n % 2 === 0) { 8 | n /= 2; 9 | } else { 10 | n = n * 3 + 1; 11 | } 12 | 13 | times++; 14 | } 15 | 16 | return times; 17 | }; 18 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/gigasecond.js: -------------------------------------------------------------------------------- 1 | const year = date => date.getUTCFullYear(); 2 | const month = date => date.getUTCMonth(); 3 | const day = date => date.getUTCDate() + 11574; 4 | const hours = date => date.getUTCHours() + 1; 5 | const minutes = date => date.getUTCMinutes() + 46; 6 | const second = date => date.getUTCSeconds() + 40; 7 | 8 | export const gigasecond = date => 9 | new Date( 10 | Date.UTC( 11 | year(date), 12 | month(date), 13 | day(date), 14 | hours(date), 15 | minutes(date), 16 | second(date) 17 | ) 18 | ); 19 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/hello-world.js: -------------------------------------------------------------------------------- 1 | export const hello = () => "Hello, World!"; 2 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/leap.js: -------------------------------------------------------------------------------- 1 | // https://exercism.io/tracks/javascript/exercises/leap/solutions/0e7bcf1db4974d159ab9ebe9e961bcd1 2 | 3 | export const isLeap = year => 4 | (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; 5 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/resistor-color.js: -------------------------------------------------------------------------------- 1 | const colorCode = color => COLORS.indexOf(color); 2 | 3 | const COLORS = [ 4 | "black", 5 | "brown", 6 | "red", 7 | "orange", 8 | "yellow", 9 | "green", 10 | "blue", 11 | "violet", 12 | "grey", 13 | "white" 14 | ]; 15 | 16 | export { colorCode, COLORS }; 17 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/resistor-colors.js: -------------------------------------------------------------------------------- 1 | // https://exercism.io/my/solutions/0a95e6a8ebb94efeac42b2c6e065818b 2 | 3 | const COLORS = [ 4 | "black", 5 | "brown", 6 | "red", 7 | "orange", 8 | "yellow", 9 | "green", 10 | "blue", 11 | "violet", 12 | "grey", 13 | "white" 14 | ]; 15 | 16 | const reducer = (acc, resistanceValue) => acc + resistanceValue; 17 | const resistanceValuesString = (resistorsColors) => 18 | resistorsColors 19 | .map((color) => COLORS.indexOf(color)) 20 | .reduce(reducer, ""); 21 | 22 | export const value = (resistorsColors) => { 23 | return Number(resistanceValuesString(resistorsColors)); 24 | }; 25 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/reverse-string.js: -------------------------------------------------------------------------------- 1 | const lastChar = str => str[str.length - 1]; 2 | 3 | export const reverseString = str => { 4 | if (str.length <= 1) { 5 | return str; 6 | } 7 | 8 | return lastChar(str) + reverseString(str.substring(0, str.length - 1)); 9 | }; 10 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/triangle.js: -------------------------------------------------------------------------------- 1 | export function Triangle(side1, side2, side3) { 2 | this.side1 = side1; 3 | this.side2 = side2; 4 | this.side3 = side3; 5 | } 6 | 7 | Triangle.prototype.isEquilateral = function() { 8 | return this.side1 == this.side2 && this.side1 == this.side3; 9 | }; 10 | 11 | Triangle.prototype.isIsosceles = function() { 12 | return ( 13 | this.side1 == this.side2 || 14 | this.side1 == this.side3 || 15 | this.side2 == this.side3 16 | ); 17 | }; 18 | 19 | Triangle.prototype.anyNonPositiveSide = function() { 20 | return this.side1 <= 0 || this.side2 <= 0 || this.side3 <= 0; 21 | }; 22 | 23 | Triangle.prototype.isInequality = function() { 24 | return ( 25 | this.side1 > this.side2 + this.side3 || 26 | this.side2 > this.side1 + this.side3 || 27 | this.side3 > this.side2 + this.side1 28 | ); 29 | }; 30 | 31 | Triangle.prototype.kind = function() { 32 | if (this.anyNonPositiveSide() || this.isInequality()) { 33 | throw "Not a triangle"; 34 | } else if (this.isEquilateral()) { 35 | return "equilateral"; 36 | } else if (this.isIsosceles()) { 37 | return "isosceles"; 38 | } else { 39 | return "scalene"; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /programming_challenges/exercism/javascript/two-fer.js: -------------------------------------------------------------------------------- 1 | export const twoFer = (name = "you") => `One for ${name}, one for me.`; 2 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/array_of_n_elements/array_of_n_elements.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-array-of-n-elements/problem 2 | 3 | (defn array-of-n-elements 4 | [n] 5 | (range n)) 6 | 7 | (array-of-n-elements 1) 8 | (array-of-n-elements 3) 9 | (array-of-n-elements 5) 10 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/array_of_n_elements/array_of_n_elements_without_range.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-array-of-n-elements/problem 2 | 3 | (defn array-of-n-elements-without-range 4 | [n] 5 | (loop [n n list []] 6 | (if (pos? n) 7 | (recur (dec n) (conj list 0)) 8 | list))) 9 | 10 | (array-of-n-elements-without-range 1) 11 | (array-of-n-elements-without-range 3) 12 | (array-of-n-elements-without-range 5) 13 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/basics/hello_world.clj: -------------------------------------------------------------------------------- 1 | ;; Problem: https://www.hackerrank.com/challenges/fp-hello-world/problem?h_r=next-challenge&h_v=zen 2 | 3 | (print "Hello World") 4 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/basics/hello_world_n_times.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-hello-world-n-times/problem 2 | 3 | (defn greater-than-zero? [n] (> n 0)) 4 | 5 | (defn hello-word-n-times 6 | [n] 7 | (if (greater-than-zero? n) 8 | (do (println "Hello World") 9 | (hello-word-n-times (dec n))))) 10 | 11 | (hello-word-n-times 4) 12 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/basics/solve_me_first.clj: -------------------------------------------------------------------------------- 1 | ;; Problem: https://www.hackerrank.com/challenges/fp-solve-me-first/problem 2 | 3 | (defn solve-me-first 4 | [a b] 5 | (+ a b)) 6 | 7 | (def a (read-line)) 8 | (def b (read-line)) 9 | 10 | (println (solve-me-first (Integer/parseInt a) (Integer/parseInt b))) 11 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/eval_ex/main.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/eval-ex/problem 2 | 3 | ;; Approach: 4 | ;; Use map to transform the list of 10 elements from x to (/ (exp x n) (factorial n)) 5 | ;; And reduce suming each element 6 | 7 | ;; For this approach, we can separate in 3 different functions 8 | ;; - exp: exponantial 9 | ;; - factorial 10 | ;; - expansion: function composed of exp and factorial passed to map 11 | 12 | ;; So we can test these 3 functions 13 | 14 | (ns eval-ex 15 | (:use [clojure.test])) 16 | 17 | (defn exp 18 | [x n] 19 | (reduce * (repeat n x))) 20 | 21 | (defn factorial 22 | [n] 23 | (reduce * (range 1 (inc n)))) 24 | 25 | (defn expansion 26 | [x] 27 | (fn [n] 28 | (/ (exp x n) (factorial n)))) 29 | 30 | (defn series-expansion 31 | [x] 32 | (read-string 33 | (format "%.4f" 34 | (reduce + (map (expansion x) (range 10)))))) 35 | 36 | ;; ----------------------------------------------------------- 37 | 38 | ;; Tests 39 | 40 | (deftest test-exp 41 | (testing "Exponantial function" 42 | (is (= 1 (exp 1 0))) 43 | (is (= 1 (exp 1 1))) 44 | (is (= 4 (exp 2 2))))) 45 | 46 | (deftest test-factorial 47 | (testing "Factorial function" 48 | (is (= 1 (factorial 0))) 49 | (is (= 1 (factorial 1))) 50 | (is (= 120 (factorial 5))))) 51 | 52 | (deftest test-expansion 53 | (testing "Expansion function" 54 | (is (= 1 ((expansion 10) 0))) 55 | (is (= 10 ((expansion 10) 1))) 56 | (is (= 50 ((expansion 10) 2))))) 57 | 58 | (deftest test-series-expansion 59 | (testing "Sample Input - Output" 60 | (is (= 2423600.1887 (series-expansion 20.0000))) 61 | (is (= 143.6895 (series-expansion 5.0000))) 62 | (is (= 1.6487 (series-expansion 0.5000))) 63 | (is (= 0.6065 (series-expansion -0.5000))))) 64 | 65 | (run-tests) 66 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/fibonacci/fibonacci.js: -------------------------------------------------------------------------------- 1 | // https://www.hackerrank.com/challenges/functional-programming-warmups-in-recursion---fibonacci-numbers/problem 2 | 3 | const fibonacci = n => { 4 | if (n === 1) return 0; 5 | if (n === 2) return 1; 6 | return fibonacci(n - 1) + fibonacci(n - 2); 7 | } 8 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/filter_array/filter_array.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-filter-array/problem 2 | 3 | (defn filter-array 4 | [n lst] 5 | (filter #(> n %) lst)) 6 | 7 | (filter-array 25 [-41 46 -28 21 52 83 -29 84 27 40]) 8 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/filter_positions_in_a_list/filter_positions_in_a_list.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-filter-positions-in-a-list/problem 2 | 3 | (defn filter-positions-in-a-list 4 | [lst] 5 | (take-nth 2 (rest lst))) 6 | 7 | (filter-positions-in-a-list []) 8 | (filter-positions-in-a-list [0 1 2]) 9 | (filter-positions-in-a-list [0 1 2 3 4 5 6 7 8 9]) 10 | (filter-positions-in-a-list [8 15 22 1 10 6 2 18 18 1]) 11 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/list_length/list_length.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-list-length/problem?h_r=next-challenge&h_v=zen 2 | 3 | (defn list-length 4 | [lst] 5 | (loop [coll lst counter 0] 6 | (if (empty? coll) 7 | counter 8 | (recur (rest coll) (inc counter))))) 9 | 10 | (list-length [0 1 2 3 4 5 6 7 8 9]) 11 | (list-length [0 1 2 -1 4 -5 6 7 -8 9]) 12 | (list-length []) 13 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/list_length/list_length_reduce.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-list-length/problem?h_r=next-challenge&h_v=zen 2 | 3 | (defn list-length 4 | [lst] 5 | (reduce + (map (constantly 1) lst))) 6 | 7 | (list-length [0 1 2 3 4 5 6 7 8 9]) 8 | (list-length [0 1 2 -1 4 -5 6 7 -8 9]) 9 | (list-length []) 10 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/list_replication/list_replication.clj: -------------------------------------------------------------------------------- 1 | ;; Problem: https://www.hackerrank.com/challenges/fp-list-replication/problem 2 | 3 | (defn list-replication 4 | [n list] 5 | (sort 6 | (flatten 7 | (repeat n list)))) 8 | 9 | (list-replication 3 [1 2 3]) 10 | (list-replication 2 [4 5]) 11 | (list-replication 1 [10 100]) 12 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/reverse_a_list/reverse_a_list.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-reverse-a-list/problem 2 | ;; last function: returns the last element of a collection 3 | ;; count function: returns the length of a collection 4 | ;; take function: returns the first N taken elements of a collection 5 | ;; not-empty function: returns true if the collection is not empty. Otherwise, false 6 | 7 | (def example-list [19 22 3 28 26 17 18 4 28 0]) 8 | 9 | (defn reverse-a-list 10 | [list] 11 | (loop [original-list list reversed-list []] 12 | (if (not-empty original-list) 13 | (recur (take (dec (count original-list)) original-list) (conj reversed-list (last original-list))) 14 | reversed-list))) 15 | 16 | (reverse-a-list example-list) 17 | 18 | ;; Implementing an anonymous function 19 | 20 | (fn [lst] 21 | (loop [original-list lst reversed-list []] 22 | (if (not-empty original-list) 23 | (recur (take (dec (count original-list)) original-list) (conj reversed-list (last original-list))) 24 | reversed-list))) 25 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/reverse_a_list/reverse_a_list_into.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-reverse-a-list/problem 2 | ;; basically, the into function is a reduce + conj 3 | 4 | (def example-list [19 22 3 28 26 17 18 4 28 0]) 5 | 6 | (defn reverse-a-list 7 | [lst] 8 | (into '() lst)) 9 | 10 | (reverse-a-list example-list) 11 | 12 | ((fn [lst] (into '() lst)) example-list) 13 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/reverse_a_list/reverse_a_list_reduce.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-reverse-a-list/problem 2 | 3 | (def example-list [19 22 3 28 26 17 18 4 28 0]) 4 | 5 | (defn reverse-a-list 6 | [lst] 7 | (reduce conj '() lst)) 8 | 9 | (reverse-a-list example-list) 10 | 11 | ;; Implementing an anonymous function 12 | 13 | ((fn [lst] (reduce conj '() lst)) example-list) 14 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/sum_of_odd_elements/sum_of_odd_elements.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-sum-of-odd-elements/problem 2 | 3 | (defn sum-of-odd-elements 4 | [lst] 5 | (reduce 6 | + 7 | (filter 8 | (odd? n) 9 | lst))) 10 | 11 | (sum-of-odd-elements [3 2 4 6 5 7 8 0 1]) 12 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/update_list/update_list.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-update-list/problem 2 | 3 | (defn to-absolute 4 | [n] 5 | (if (neg? n) 6 | (+ (* n -2) n) 7 | n)) 8 | 9 | (defn add-element-from-list-to-list 10 | [lst1 lst2] 11 | (conj lst2 (to-absolute (first lst1)))) 12 | 13 | (defn update-list 14 | [lst] 15 | (loop [original-list lst absolute-list []] 16 | (if (empty? original-list) 17 | absolute-list 18 | (recur 19 | (rest original-list) 20 | (add-element-from-list-to-list original-list absolute-list))))) 21 | 22 | (update-list []) 23 | (update-list [1 2 3 4 5]) 24 | (update-list [-1 -2 -3 -4 -5]) 25 | (update-list [1 -2 3 -4 5]) 26 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/update_list/update_list_anonymous.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-update-list/problem 2 | 3 | (fn 4 | [lst] 5 | (loop [original-list lst absolute-list []] 6 | (if (empty? original-list) 7 | absolute-list 8 | (recur 9 | (rest original-list) 10 | (conj 11 | absolute-list 12 | (if (< (first original-list) 0) 13 | (+ (* (first original-list) -2) (first original-list)) 14 | (first original-list))))))) 15 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/update_list/update_list_map.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-update-list/problem 2 | 3 | (defn to-absolute 4 | [n] 5 | (if (neg? n) 6 | (+ (* n -2) n) 7 | n)) 8 | 9 | (defn update-list-map 10 | [lst] 11 | (map to-absolute lst)) 12 | 13 | (update-list-map []) 14 | (update-list-map [1 2 3 4 5]) 15 | (update-list-map [-1 -2 -3 -4 -5]) 16 | (update-list-map [1 -2 3 -4 5]) 17 | -------------------------------------------------------------------------------- /programming_challenges/hacker_rank/update_list/update_list_map_anonymous.clj: -------------------------------------------------------------------------------- 1 | ;; https://www.hackerrank.com/challenges/fp-update-list/problem 2 | 3 | (fn 4 | [lst] 5 | (map 6 | (fn 7 | [n] 8 | (if (neg? n) 9 | (+ (* n -2) n) 10 | n)) 11 | lst)) 12 | -------------------------------------------------------------------------------- /programming_challenges/playground/collisions.clj: -------------------------------------------------------------------------------- 1 | (ns collisions.core 2 | (:require [clojure.string :as str]) 3 | (:gen-class)) 4 | 5 | (defn str->edge [s] 6 | (->> (str/split s #" ") 7 | (map #(Integer/parseInt %)))) 8 | 9 | (defn file-contents->edges [s] 10 | (->> (str/split s #"\n") 11 | (map str->edge))) 12 | 13 | (defn edge->adj-list [[u v]] 14 | {u #{v}, v #{u}}) 15 | 16 | (defn with-new-connections [adj-list new-connections] 17 | (merge-with into adj-list new-connections)) 18 | 19 | (defn with-new-edge [adj-list edge] 20 | (->> (edge->adj-list edge) 21 | (with-new-connections adj-list))) 22 | 23 | (defn edges->adj-list [edges] 24 | (reduce with-new-edge {} edges)) 25 | 26 | (defn same-network? [a b adj-list] 27 | (loop [[curr & rest] (list a), visited? #{}] 28 | (when curr 29 | (or (= curr b) 30 | (recur (->> (adj-list curr) 31 | (filter (complement visited?)) 32 | (into rest)) 33 | (conj visited? curr)))))) 34 | 35 | (defn -main 36 | [file-path a b] 37 | (if (-> (slurp file-path) 38 | file-contents->edges 39 | edges->adj-list 40 | (->> (same-network? (Integer/parseInt a) (Integer/parseInt b)))) 41 | (println "yup") 42 | (println "nah"))) 43 | -------------------------------------------------------------------------------- /programming_challenges/playground/jobs/job.clj: -------------------------------------------------------------------------------- 1 | ;; -- jobs and agents definition -- 2 | (def jobs 3 | [{:id "f26e890b-df8e-422e-a39c-7762aa0bac36" :type "rewards-question" :urgent false} 4 | {:id "690de6bc-163c-4345-bf6f-25dd0c58e864" :type "bills-questions" :urgent false} 5 | {:id "c0033410-981c-428a-954a-35dec05ef1d2" :type "bills-questions" :urgent true}]) 6 | 7 | (def agents 8 | [{:id "8ab86c18-3fae-4804-bfd9-c3d6e8f66260" 9 | :name "BoJack Horseman" 10 | :primary_skillset ["bills-questions"] 11 | :secondary_skillset []} 12 | {:id "ed0e23ef-6c2b-430c-9b90-cd4f1ff74c88" 13 | :name "Mr. Peanut Butter" 14 | :primary_skillset ["rewards-question"] 15 | :secondary_skillset ["bills-questions"]}]) 16 | ;; -- end of jobs and agents definition -- 17 | 18 | ;; -- sorting by urgency -- 19 | (defn prioritize 20 | [jobs] 21 | (sort-by (complement :urgent) jobs)) 22 | 23 | (prioritize jobs) 24 | ;; -- end of sorting by urgency -- 25 | 26 | ;; -- filtering by skillsets -- 27 | (def first-job (first jobs)) 28 | (def second-job (second jobs)) 29 | 30 | (defn by-skillset 31 | [job agent] 32 | (or 33 | (some #(= (:type job) %) (:primary_skillset agent)) 34 | (some #(= (:type job) %) (:secondary_skillset agent)))) 35 | 36 | (defn filter-by-skillset 37 | [agents job] 38 | (filter (partial by-skillset job) agents)) 39 | ;; -- end of filtering by skillsets -- 40 | 41 | ;; -- examples of function use -- 42 | (filter-by-skillset agents first-job) 43 | (filter-by-skillset agents second-job) 44 | (filter-by-skillset (conj agents {:id "123" :name "Mr. Nothing" :primary_skillset ["nothing-other"] :secondary_skillset ["nothing"]}) second-job) 45 | ;; -- end of examples of function use -- 46 | 47 | ;; -- sorting by job type -- 48 | (defn agent-has-job-type-as-primary-skillset? 49 | [job-type agent] 50 | (if (some #{job-type} (:primary_skillset agent)) 0 1)) 51 | 52 | (defn add-contains-primary-skillset 53 | [job-type agent] 54 | (assoc 55 | agent 56 | :contains-primary-skillset? 57 | (agent-has-job-type-as-primary-skillset? job-type agent))) 58 | 59 | (defn remove-contains-primary-skillset 60 | [agent] 61 | (dissoc agent :contains-primary-skillset?)) 62 | 63 | (defn sort-agents-by-primary-skillset 64 | [agents job] 65 | (->> agents 66 | (map (partial add-contains-primary-skillset (:type job))) 67 | (sort-by :contains-primary-skillset?) 68 | (map remove-contains-primary-skillset))) 69 | 70 | (defn agents-to-be-assigned 71 | [agents job] 72 | (-> agents 73 | (filter-by-skillset job) 74 | (sort-agents-by-primary-skillset job))) 75 | 76 | (defn agents-ids 77 | [assigned-jobs] 78 | (map 79 | #(get-in % [:job_assigned :agent_id]) 80 | assigned-jobs)) 81 | 82 | (defn find-agent-id? 83 | [assigned-jobs agent] 84 | (some 85 | #(= (:id agent) %) 86 | (agents-ids assigned-jobs))) 87 | 88 | (defn assigned? 89 | [assigned-jobs agent] 90 | (find-agent-id? assigned-jobs agent)) 91 | 92 | (defn not-assigned? 93 | [assigned-jobs agent] 94 | ((complement assigned?) assigned-jobs agent)) 95 | 96 | (defn make-agent-job-assignment 97 | [job agent] 98 | {:job_assigned 99 | {:job_id (:id job) 100 | :agent_id (:id agent)}}) 101 | 102 | (defn assignments 103 | [assigned-jobs job new-assignment] 104 | (if (nil? new-assignment) 105 | assigned-jobs 106 | (conj 107 | assigned-jobs 108 | (make-agent-job-assignment 109 | job 110 | new-assignment)))) 111 | 112 | (defn assign-agent 113 | [agents job assigned-jobs] 114 | (->> (agents-to-be-assigned agents job) 115 | (filter (partial not-assigned? assigned-jobs)) 116 | (first) 117 | (assignments assigned-jobs job))) 118 | 119 | ;; ----- Testing sorted agents ----- 120 | (defn testing [agents jobs assigned-jobs] 121 | (loop 122 | [agents agents 123 | jobs (prioritize jobs) 124 | assigned-jobs assigned-jobs] 125 | 126 | (if (not-empty jobs) 127 | (do 128 | (println (str "----- " (:type (first jobs)) " -----")) 129 | (recur 130 | agents 131 | (rest jobs) 132 | (assign-agent agents (first jobs) assigned-jobs))) 133 | 134 | assigned-jobs))) 135 | 136 | (pprint (testing agents jobs [])) 137 | ;; ----- end of Testing sorted agents ----- 138 | -------------------------------------------------------------------------------- /programming_challenges/playground/jobs/resource/input.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "new_agent": { 4 | "id": "8ab86c18-3fae-4804-bfd9-c3d6e8f66260", 5 | "name": "BoJack Horseman", 6 | "primary_skillset": [ 7 | "bills-questions" 8 | ], 9 | "secondary_skillset": [] 10 | } 11 | }, 12 | { 13 | "new_job": { 14 | "id": "f26e890b-df8e-422e-a39c-7762aa0bac36", 15 | "type": "rewards-question", 16 | "urgent": false 17 | } 18 | }, 19 | { 20 | "new_agent": { 21 | "id": "ed0e23ef-6c2b-430c-9b90-cd4f1ff74c88", 22 | "name": "Mr. Peanut Butter", 23 | "primary_skillset": [ 24 | "rewards-question" 25 | ], 26 | "secondary_skillset": [ 27 | "bills-questions" 28 | ] 29 | } 30 | }, 31 | { 32 | "new_job": { 33 | "id": "690de6bc-163c-4345-bf6f-25dd0c58e864", 34 | "type": "bills-questions", 35 | "urgent": false 36 | } 37 | }, 38 | { 39 | "new_job": { 40 | "id": "c0033410-981c-428a-954a-35dec05ef1d2", 41 | "type": "bills-questions", 42 | "urgent": true 43 | } 44 | }, 45 | { 46 | "job_request": { 47 | "agent_id": "8ab86c18-3fae-4804-bfd9-c3d6e8f66260" 48 | } 49 | }, 50 | { 51 | "job_request": { 52 | "agent_id": "ed0e23ef-6c2b-430c-9b90-cd4f1ff74c88" 53 | } 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /programming_challenges/playground/jobs/resource/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "job_assigned": { 4 | "job_id": "c0033410-981c-428a-954a-35dec05ef1d2", 5 | "agent_id": "8ab86c18-3fae-4804-bfd9-c3d6e8f66260" 6 | } 7 | }, 8 | { 9 | "job_assigned": { 10 | "job_id": "f26e890b-df8e-422e-a39c-7762aa0bac36", 11 | "agent_id": "ed0e23ef-6c2b-430c-9b90-cd4f1ff74c88" 12 | } 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Python Resources 4 | 5 | ## Posts 6 | 7 | - [Python funcional: Quase um livro, quase um tutorial](https://github.com/dunossauro/python-funcional) 8 | - [Learn Functional Python in 10 Minutes](https://hackernoon.com/learn-functional-python-in-10-minutes-to-2d1651dece6f) 9 | - [Introduction to Functional Programming in Python](https://www.dataquest.io/blog/introduction-functional-programming-python/) 10 | - [A practical introduction to functional programming in Python](https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming) 11 | - [Official Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) 12 | - [Immutable data structures in Python](https://www.theguardian.com/info/developer-blog/2014/oct/21/immutable-data-structures-in-python) 13 | - [Best Practices for Using Functional Programming in Python](https://kite.com/blog/python/functional-programming) 14 | 15 | ## Talks 16 | 17 | - [Immutable Programming Writing Functional Python](https://www.youtube.com/watch?v=_OLEVvjrIj8&ab_channel=PyCon2017) 18 | 19 | ## Books 20 | 21 | - [Functional Programming in Python](https://www.oreilly.com/programming/free/files/functional-programming-python.pdf) 22 | 23 | 24 | -------------------------------------------------------------------------------- /python/intro.py: -------------------------------------------------------------------------------- 1 | # Assign functions to a variable 2 | def add(a, b): 3 | return a + b 4 | 5 | 6 | plus = add 7 | value = plus(1, 2) 8 | print(value) # 3 9 | 10 | # Lambda 11 | value = (lambda a, b: a + b)(1, 2) 12 | print(value) # 3 13 | 14 | addition = lambda a, b: a + b 15 | value = addition(1, 2) 16 | print(value) # 3 17 | 18 | authors = [ 19 | 'Octavia Butler', 20 | 'Isaac Asimov', 21 | 'Neal Stephenson', 22 | 'Margaret Atwood', 23 | 'Usula K Le Guin', 24 | 'Ray Bradbury' 25 | ] 26 | 27 | sorted_authors_by_name_length = sorted(authors, key=len) 28 | print(sorted_authors_by_name_length) 29 | 30 | sorted_authors_by_last_name = sorted(authors, key=lambda name: name.split()[-1]) 31 | print(sorted_authors_by_last_name) 32 | -------------------------------------------------------------------------------- /ruby/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Ruby Resources 4 | 5 | - [Programação funcional que funciona por Rodrigo Serradura](https://www.youtube.com/watch?v=w1OwYWe4UFo&ab_channel=GURUSPtalks) 6 | - [Programação funcional com Ruby, potencialize e simplifique qualquer codebase](https://speakerdeck.com/serradura/programacao-funcional-com-ruby-potencialize-e-simplifique-qualquer-codebase?slide=126) 7 | - [Ruby Functional Programming](https://github.com/tokland/tokland/wiki/RubyFunctionalProgramming) 8 | - [Applications of Lambda in Ruby](http://jetrockets.pro/blog/lambda) 9 | - [What’s new in Ruby 2.6?](https://medium.com/tailor-tech/whats-new-in-ruby-2-6-a4774f3631c1) 10 | - [Using `yield_self` for composable ActiveRecord relations](https://robots.thoughtbot.com/using-yieldself-for-composable-activerecord-relations) 11 | - [yield_self is more awesome than you could think](https://zverok.github.io/blog/2018-01-24-yield_self.html) 12 | - [Exploring Ruby 2.6 — Proc#compose and Enumerator#chain](https://medium.com/@baweaver/exploring-ruby-2-6-proc-compose-and-enumerator-chain-49f10e237542) 13 | 14 | 15 | -------------------------------------------------------------------------------- /ruby/immutable_array.rb: -------------------------------------------------------------------------------- 1 | # Push: mutable 2 | list = [1, 2, 3] 3 | list.push(4) 4 | list # [1, 2, 3, 4] 5 | 6 | # <<: mutable 7 | list = [1, 2, 3] 8 | list << 4 9 | list # [1, 2, 3, 4] 10 | 11 | # +: immutable 12 | list = [1, 2, 3] 13 | list + [4] # [1, 2, 3, 4] 14 | list # [1, 2, 3] 15 | -------------------------------------------------------------------------------- /ruby/immutable_select_with_reduce.rb: -------------------------------------------------------------------------------- 1 | def select(list, fn) 2 | list.reduce([]) { |acc, n| fn[n] ? acc + [n] : acc } 3 | end 4 | 5 | even = -> n { n % 2 == 0 } 6 | list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 7 | 8 | select(list, even) # [2, 4, 6, 8, 10] -------------------------------------------------------------------------------- /rust/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Rust Functional Programming 4 | 5 | ## Table of Content 6 | 7 | - [General](#general) 8 | - [Books](#books) 9 | 10 | ## General 11 | 12 | - [Functional Language Features: Iterators and Closures](https://doc.rust-lang.org/book/ch13-00-functional-features.html) 13 | 14 | ## Books 15 | 16 | - [Programação Funcional e Concorrente em Rust](https://www.casadocodigo.com.br/products/livro-rust-funcional-concorrente) 17 | 18 | 19 | --------------------------------------------------------------------------------