{"id":26194332,"url":"https://github.com/active-group/reacl-pointfree","last_synced_at":"2025-10-26T19:07:42.877Z","repository":{"id":70845729,"uuid":"181475723","full_name":"active-group/reacl-pointfree","owner":"active-group","description":null,"archived":false,"fork":false,"pushed_at":"2019-08-02T16:45:30.000Z","size":8,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-12T01:56:10.818Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/active-group.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-04-15T11:48:10.000Z","updated_at":"2019-08-02T16:45:31.000Z","dependencies_parsed_at":"2023-02-22T01:16:27.146Z","dependency_job_id":null,"html_url":"https://github.com/active-group/reacl-pointfree","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/active-group/reacl-pointfree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/active-group%2Freacl-pointfree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/active-group%2Freacl-pointfree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/active-group%2Freacl-pointfree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/active-group%2Freacl-pointfree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/active-group","download_url":"https://codeload.github.com/active-group/reacl-pointfree/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/active-group%2Freacl-pointfree/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268147501,"owners_count":24203280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-31T02:00:08.723Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-12T01:56:12.524Z","updated_at":"2025-10-26T19:07:42.581Z","avatar_url":"https://github.com/active-group.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reacl pointfree style\n\nThis project demonstrates pointfree component composition. A style of\nprogramming with Reacl components.\n\n## Background: pointfree function composition\n\nFunctions can be composed by applying them to explicitly named\narguments inside a lambda:\n\n```clojure\n(defn not-zero? [x]\n  (not (zero? x)))\n```\n\nAlternatively, you can also compose functions by using function\ncombinators such as `partial`, `comp`, etc.\n\n```clojure\n(def not-zero? (comp not zero?))\n```\n\n## Pointfree component composition\n\nReacl components can be composed in similar ways and in similar\nstyles. In most cases we take to the point-based style.\n\n```clojure\n(defclass to-do-item this item []\n\n  render\n  (div\n   (checkbox\n    (opt :embed-app-state (fn [i d] (assoc i :done? d)))\n    (:done? item))\n\n   (text-input\n    (opt :embed-app-state (fn [i t] (assoc i :text t)))\n    (:text item))))\n```\n\nBut at some instances we may be better served by a pointfree\ndefinition:\n\n```clojure\n(def to-do-item\n  (p/div\n   (p/focus :done? checkbox)\n   (p/focus :text text-input)))\n```\n\nHere, `p/div` is a higher-order component that just wraps its arguments\nin a `dom/div`. App-state is not transformed at all. In contrast,\n`focus` is a higher-order component that takes a lens and a\nsubcomponent and returns a component that manages the subcomponent's\napp-state according to the lens.\n\n```clojure\n(defn focus [lens component]\n  (class\n   \"focus\"\n   this\n   app-state\n   [\u0026 args]\n\n   handle-message\n   (fn [sub]\n     (return\n      :app-state (lens/shove app-state lens sub)))\n\n   render\n   (apply\n    component\n    (opt\n     :reaction\n     (pass-through-reaction this))\n    (lens/yank app-state lens)\n    args)))\n```\n\nThis project provides a set of combinators for Reacl components in\n`pointfree.pointfree` and a simple example of their usage in\n`pointfree.core`. The usual caveats of higher-order components apply.\n\n\n## Discussion\n\nWith the point-based style we give the input app-state a name that is\nbound to a value at runtime.\n\n```clojure\n(defclass to-do-item this item ...)\n```\n\nThis is similar to naming arguments in a function definition and is\ntherefore easy to understand. However, components must do more work\nthan functions. In addition to an input (\"downward\") app-state we must\nalso specify what happens with output (\"upward\") app-state.\n\n```clojure\n...\nrender\n...\n (checkbox\n  (opt :embed-app-state (fn [i d] (assoc i :done? d)))\n  (:done? item))\n...\n```\n\nWith `:embed-app-state` we specify the upward flow of app-state.\nStill, syntactically, we specify this flow as an option that we pass\n\"down\".\n\nIn pointfree style we can avoid this awkwardness with a careful design\nof the combinators. `focus` is a perfect example. A lens is all it\ntakes to fully specify both upward and downward flow of app-state.\n\n\n### Local state\n\nWe have not yet found a satisfying way of dealing with local-state in\npointfree style. We might need to get rid of the concept\nentirely in order to find a more principled solution for the problems\nthat we currently try to solve with local-state.\n\n\n### Names\n\nWithout rigid static types, the inputs of pointfree definitions are\nharder to infer than with point-based definitions, which give the\nreader the names of the inputs as one more data point. You should\nprobably either specify the input types via comments, `:pre`, specs or\nby giving the definition itself a more descriptive name.\n\n```clojure\n(defrecord Todo [done? text id])\n\n(def todo-component\n  (p/div\n   (p/focus :done? checkbox)\n   (p/focus :text text-input)))\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factive-group%2Freacl-pointfree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Factive-group%2Freacl-pointfree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factive-group%2Freacl-pointfree/lists"}