metaboulie commited on
Commit
48feff6
·
1 Parent(s): e3bcacf

refactor(applicatives): remove `sequenceL` from `Applicative` because it should be a classmethod but can't be generically implemented

Browse files
functional_programming/06_applicatives.py CHANGED
@@ -7,9 +7,10 @@
7
 
8
  import marimo
9
 
10
- __generated_with = "0.12.0"
11
  app = marimo.App(app_title="Applicative programming with effects")
12
 
 
13
  @app.cell(hide_code=True)
14
  def _(mo):
15
  mo.md(
@@ -33,10 +34,9 @@ def _(mo):
33
  /// details | Notebook metadata
34
  type: info
35
 
36
- version: 0.1.0 | last modified: 2025-04-02 | author: [métaboulie](https://github.com/metaboulie)<br/>
37
 
38
  ///
39
-
40
  """
41
  )
42
  return
@@ -74,7 +74,7 @@ def _(mo):
74
  def _(mo):
75
  mo.md(
76
  r"""
77
- ## Defining multifunctor
78
 
79
  As a result, we may want to define a single `Multifunctor` such that:
80
 
@@ -263,7 +263,7 @@ def _(mo):
263
 
264
  - `apply` should apply a *wrapped* function to a *wrapper* value
265
 
266
- The implementation is:
267
  """
268
  )
269
  return
@@ -379,7 +379,7 @@ def _(mo):
379
  - if the function is `None`, apply returns `None`
380
  - else apply the function to the value and wrap the result in `Just`
381
 
382
- The implementation is:
383
  """
384
  )
385
  return
@@ -561,6 +561,10 @@ def _(mo):
561
  r"""
562
  ## Utility functions
563
 
 
 
 
 
564
  ```python
565
  @dataclass
566
  class Applicative[A](Functor, ABC):
@@ -748,7 +752,7 @@ def _(
748
  def _(mo):
749
  mo.md(
750
  r"""
751
- # Effectful Programming
752
 
753
  Our original motivation for applicatives was the desire the generalise the idea of mapping to functions with multiple arguments. This is a valid interpretation of the concept of applicatives, but from the three instances we have seen it becomes clear that there is also another, more abstract view.
754
 
@@ -777,7 +781,7 @@ def _(mo):
777
 
778
  - `apply` should perform an action that produces a function and perform an action that produces a value, then call the function with the value
779
 
780
- The implementation is:
781
  """
782
  )
783
  return
@@ -829,69 +833,6 @@ def _():
829
  return
830
 
831
 
832
- @app.cell(hide_code=True)
833
- def _(mo):
834
- mo.md(r"""## Collect the sequence of response with sequenceL""")
835
- return
836
-
837
-
838
- @app.cell(hide_code=True)
839
- def _(mo):
840
- mo.md(
841
- r"""
842
- One often wants to execute a sequence of commands and collect the sequence of their response, and we can define a function `sequenceL` for this
843
-
844
- /// admonition
845
- sequenceL actually means that
846
-
847
- > execute a list of commands and collect the list of their response
848
- ///
849
- """
850
- )
851
- return
852
-
853
-
854
- @app.cell
855
- def _(A, Applicative):
856
- def sequenceL(actions: list[Applicative[A]], ap) -> Applicative[list[A]]:
857
- if not actions:
858
- return ap.pure([])
859
-
860
- return ap.lift(
861
- lambda: lambda l1: lambda: lambda l2: list(l1) + list(l2),
862
- actions[0],
863
- sequenceL(actions[1:], ap),
864
- )
865
- return (sequenceL,)
866
-
867
-
868
- @app.cell(hide_code=True)
869
- def _(mo):
870
- mo.md(
871
- r"""
872
- This function transforms a list of applicative actions into a single such action that returns a list of result values, and captures a common pattern of applicative programming.
873
-
874
- And we can rewrite the `get_chars` more concisely:
875
- """
876
- )
877
- return
878
-
879
-
880
- @app.cell
881
- def _(IO, sequenceL):
882
- def get_chars_sequenceL(n: int = 3):
883
- return sequenceL(
884
- [IO.pure(input(f"input the {i}th str") for i in range(1, n + 1))], IO
885
- )
886
- return (get_chars_sequenceL,)
887
-
888
-
889
- @app.cell
890
- def _():
891
- # print(get_chars_sequenceL()())
892
- return
893
-
894
-
895
  @app.cell(hide_code=True)
896
  def _(mo):
897
  mo.md(r"""# From the perspective of category theory""")
@@ -904,7 +845,7 @@ def _(mo):
904
  r"""
905
  ## Lax Monoidal Functor
906
 
907
- An alternative, equivalent formulation of `Applicative` is given by
908
  """
909
  )
910
  return
@@ -928,12 +869,6 @@ def _(ABC, Functor, abstractmethod, dataclass):
928
  return (Monoidal,)
929
 
930
 
931
- @app.cell
932
- def _(mo):
933
- mo.md(r"""fmap g fa = fmap (g . snd) (unit ** fa)""")
934
- return
935
-
936
-
937
  @app.cell(hide_code=True)
938
  def _(mo):
939
  mo.md(
@@ -943,7 +878,7 @@ def _(mo):
943
  - `unit` provides the identity element
944
  - `tensor` combines two contexts into a product context
945
 
946
- More technically, the idea is that `monoidal functor` preserves the "monoidal structure" given by the pairing constructor `(,)` and unit type `()`.
947
  """
948
  )
949
  return
@@ -991,7 +926,7 @@ def _(mo):
991
  def _(mo):
992
  mo.md(
993
  r"""
994
- ## Mutual Definability of Monoidal and Applicative
995
 
996
  We can implement `pure` and `apply` in terms of `unit` and `tensor`, and vice versa.
997
 
 
7
 
8
  import marimo
9
 
10
+ __generated_with = "0.12.4"
11
  app = marimo.App(app_title="Applicative programming with effects")
12
 
13
+
14
  @app.cell(hide_code=True)
15
  def _(mo):
16
  mo.md(
 
34
  /// details | Notebook metadata
35
  type: info
36
 
37
+ version: 0.1.1 | last modified: 2025-04-06 | author: [métaboulie](https://github.com/metaboulie)<br/>
38
 
39
  ///
 
40
  """
41
  )
42
  return
 
74
  def _(mo):
75
  mo.md(
76
  r"""
77
+ ## Defining Multifunctor
78
 
79
  As a result, we may want to define a single `Multifunctor` such that:
80
 
 
263
 
264
  - `apply` should apply a *wrapped* function to a *wrapper* value
265
 
266
+ The implementation is:
267
  """
268
  )
269
  return
 
379
  - if the function is `None`, apply returns `None`
380
  - else apply the function to the value and wrap the result in `Just`
381
 
382
+ The implementation is:
383
  """
384
  )
385
  return
 
561
  r"""
562
  ## Utility functions
563
 
564
+ /// attention
565
+ `fmap` is defined automatically using `pure` and `apply`, so you can use `fmap` with any `Applicative`
566
+ ///
567
+
568
  ```python
569
  @dataclass
570
  class Applicative[A](Functor, ABC):
 
752
  def _(mo):
753
  mo.md(
754
  r"""
755
+ # Effectful programming
756
 
757
  Our original motivation for applicatives was the desire the generalise the idea of mapping to functions with multiple arguments. This is a valid interpretation of the concept of applicatives, but from the three instances we have seen it becomes clear that there is also another, more abstract view.
758
 
 
781
 
782
  - `apply` should perform an action that produces a function and perform an action that produces a value, then call the function with the value
783
 
784
+ The implementation is:
785
  """
786
  )
787
  return
 
833
  return
834
 
835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836
  @app.cell(hide_code=True)
837
  def _(mo):
838
  mo.md(r"""# From the perspective of category theory""")
 
845
  r"""
846
  ## Lax Monoidal Functor
847
 
848
+ An alternative, equivalent formulation of `Applicative` is given by
849
  """
850
  )
851
  return
 
869
  return (Monoidal,)
870
 
871
 
 
 
 
 
 
 
872
  @app.cell(hide_code=True)
873
  def _(mo):
874
  mo.md(
 
878
  - `unit` provides the identity element
879
  - `tensor` combines two contexts into a product context
880
 
881
+ More technically, the idea is that `monoidal functor` preserves the "monoidal structure" given by the pairing constructor `(,)` and unit type `()`.
882
  """
883
  )
884
  return
 
926
  def _(mo):
927
  mo.md(
928
  r"""
929
+ ## Mutual definability of Monoidal and Applicative
930
 
931
  We can implement `pure` and `apply` in terms of `unit` and `tensor`, and vice versa.
932
 
functional_programming/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
  # Changelog of the functional-programming course
2
 
 
 
 
 
3
  ## 2025-04-02
4
 
5
  * `0.1.0` version of notebook `06_applicatives.py`
 
1
  # Changelog of the functional-programming course
2
 
3
+ ## 2025-04-06
4
+
5
+ - remove `sequenceL` from `Applicative` because it should be a classmethod but can't be generically implemented
6
+
7
  ## 2025-04-02
8
 
9
  * `0.1.0` version of notebook `06_applicatives.py`