Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ianj-als/pypeline.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Johnson <ian.johnson@appliedlanguage.com>2012-09-11 19:21:25 +0400
committerIan Johnson <ian.johnson@appliedlanguage.com>2012-09-11 19:21:25 +0400
commit00a61feb61b21c823c41c601b08723a771194f32 (patch)
tree65e75a048d3fe26b67d173658f550d60e513e6a6
parenta648c962cbd20c6bff948b6ae716aba03e8a252d (diff)
Kleisli choice arrow added.
-rw-r--r--.gitignore1
-rw-r--r--src/pypeline/core/arrows/function_arrow.py1
-rw-r--r--src/pypeline/core/arrows/kleisli_arrow.py1
-rw-r--r--src/pypeline/core/arrows/kleisli_arrow_choice.py65
-rw-r--r--src/pypeline/core/arrows/tests/kleisli_arrow_choice_test.py175
5 files changed, 243 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 8ab72c5..5da0b3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.py[co~]
+*.md~
# Packages
*.egg
diff --git a/src/pypeline/core/arrows/function_arrow.py b/src/pypeline/core/arrows/function_arrow.py
index 5746429..17e282d 100644
--- a/src/pypeline/core/arrows/function_arrow.py
+++ b/src/pypeline/core/arrows/function_arrow.py
@@ -48,6 +48,7 @@ class FunctionArrow(Arrow):
type(func) is not types.MethodType:
raise ValueError("Must be a function or method")
+ Arrow.__init__(self)
self._func = func
#
diff --git a/src/pypeline/core/arrows/kleisli_arrow.py b/src/pypeline/core/arrows/kleisli_arrow.py
index aed24eb..344641a 100644
--- a/src/pypeline/core/arrows/kleisli_arrow.py
+++ b/src/pypeline/core/arrows/kleisli_arrow.py
@@ -40,6 +40,7 @@ class KleisliArrow(Arrow):
not isinstance(f, types.MethodType)):
raise ValueError("Function must be a function")
+ Arrow.__init__(self)
self._patcher = patcher
self._func = f
diff --git a/src/pypeline/core/arrows/kleisli_arrow_choice.py b/src/pypeline/core/arrows/kleisli_arrow_choice.py
new file mode 100644
index 0000000..aba2d4e
--- /dev/null
+++ b/src/pypeline/core/arrows/kleisli_arrow_choice.py
@@ -0,0 +1,65 @@
+#
+# Copyright Applied Language Solutions 2012
+#
+# This file is part of Pypeline.
+#
+# Pypeline is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pypeline is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pypeline. If not, see <http://www.gnu.org/licenses/>.
+#
+from pypeline.core.arrows.arrow import Arrow, ArrowChoice
+from pypeline.core.arrows.kleisli_arrow import KleisliArrow
+from pypeline.core.types.either import *
+
+
+class KleisliArrowChoice(ArrowChoice, KleisliArrow):
+ def __init__(self, patcher, f):
+ ArrowChoice.__init__(self)
+ KleisliArrow.__init__(self, patcher, f)
+
+ # left :: a b c -> a (Either b d) (Either c d)
+ def left(self):
+ def left_func(either):
+ if isinstance(either, Left):
+ return self._func(either.val) >= (lambda a: self._patcher(Left(a)))
+ elif isinstance(either, Right):
+ return self._patcher(either)
+ else:
+ raise ValueError("Must be of type Either")
+
+ return KleisliArrowChoice(self._patcher, left_func)
+
+ # right :: a b c -> a (Either d b) (Either d c)
+ def right(self):
+ def right_func(either):
+ if isinstance(either, Right):
+ return self._func(either.val) >= (lambda a: self._patcher(Right(a)))
+ elif isinstance(either, Left):
+ return self._patcher(either)
+ else:
+ raise ValueError("Must be of type Either")
+
+ return KleisliArrowChoice(self._patcher, right_func)
+
+ # (+++) :: a b c -> a b' c' -> a (Either b b') (Either c c')
+ def __add__(self, other):
+ if not isinstance(other, KleisliArrowChoice):
+ raise ValueError("Must be a KleisliArrowChoice")
+
+ return self.left() >> other.right()
+
+ # (|||) :: a b d -> a c d -> a (Either b c) d
+ def __or__(self, other):
+ if not isinstance(other, KleisliArrowChoice):
+ raise ValueError("Must be a KleisliArrowChoice")
+
+ return (self + other) >> KleisliArrow(other._patcher, lambda either: self._patcher(either.val))
diff --git a/src/pypeline/core/arrows/tests/kleisli_arrow_choice_test.py b/src/pypeline/core/arrows/tests/kleisli_arrow_choice_test.py
new file mode 100644
index 0000000..0678720
--- /dev/null
+++ b/src/pypeline/core/arrows/tests/kleisli_arrow_choice_test.py
@@ -0,0 +1,175 @@
+#
+# Copyright Applied Language Solutions 2012
+#
+# This file is part of Pypeline.
+#
+# Pypeline is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pypeline is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pypeline. If not, see <http://www.gnu.org/licenses/>.
+#
+import unittest
+
+from pypeline.core.arrows.function_arrow import FunctionArrow
+from pypeline.core.arrows.kleisli_arrow_choice import KleisliArrowChoice
+from pypeline.core.arrows.kleisli_arrow import KleisliArrow, split as kleisli_split, unsplit as kleisli_unsplit
+from pypeline.core.types.either import Left, Right
+from pypeline.core.types.just import Just, return_ as just_return
+from pypeline.core.types.state import State, return_ as state_return
+
+
+class KleisliArrowChoiceUnitTest(unittest.TestCase):
+ def test_left_with_maybe_monad(self):
+ value = 9
+ f = lambda x: x * 9
+ k = KleisliArrowChoice(just_return, lambda a: Just(f(a))).left()
+
+ left = KleisliArrow.runKleisli(k, Left(value))
+ self.assertEquals(Just(Left(f(value))), left)
+
+ right = KleisliArrow.runKleisli(k, Right(value))
+ self.assertEquals(Just(Right(value)), right)
+
+
+ def test_left_with_state_monad(self):
+ s1 = "*2"
+ w = lambda a: a * 2
+ f = lambda a: State(lambda s: (w(a), s.append(s1) or s))
+ k = KleisliArrowChoice(state_return, f).left()
+
+ value = 3.141
+ left_state = KleisliArrow.runKleisli(k, Left(value))
+ left = State.runState(left_state, [])
+ left_target = (Left(w(value)), [s1])
+ self.assertEquals(left_target, left)
+
+ right_state = KleisliArrow.runKleisli(k, Right(value))
+ right = State.runState(right_state, [])
+ right_target = (Right(value), [])
+ self.assertEquals(right_target, right)
+
+
+ def test_right_with_maybe_monad(self):
+ value = 9
+ f = lambda x: x * 9
+ k = KleisliArrowChoice(just_return, lambda a: Just(f(a))).right()
+
+ left = KleisliArrow.runKleisli(k, Left(value))
+ self.assertEquals(Just(Left(value)), left)
+
+ right = KleisliArrow.runKleisli(k, Right(value))
+ self.assertEquals(Just(Right(f(value))), right)
+
+
+ def test_right_with_state_monad(self):
+ s1 = "*2"
+ w = lambda a: a * 2
+ f = lambda a: State(lambda s: (w(a), s.append(s1) or s))
+ k = KleisliArrowChoice(state_return, f).right()
+
+ value = 3.141
+ left_state = KleisliArrow.runKleisli(k, Left(value))
+ left = State.runState(left_state, [])
+ left_target = (Left(value), [])
+ self.assertEquals(left_target, left)
+
+ right_state = KleisliArrow.runKleisli(k, Right(value))
+ right = State.runState(right_state, [])
+ right_target = (Right(w(value)), [s1])
+ self.assertEquals(right_target, right)
+
+
+ def test_triple_add_with_maybe_monad(self):
+ value = 11
+ f = lambda x: x * 9
+ k1 = KleisliArrowChoice(just_return, lambda a: Just(f(a)))
+
+ h = lambda x: x - 9
+ k2 = KleisliArrowChoice(just_return, lambda a: Just(h(a)))
+
+ arrow = k1 + k2
+
+ left = KleisliArrow.runKleisli(arrow, Left(value))
+ left_target = Just(Left(f(value)))
+ self.assertEquals(left_target, left)
+
+ right = KleisliArrow.runKleisli(arrow, Right(value))
+ right_target = Just(Right(h(value)))
+ self.assertEquals(right_target, right)
+
+
+ def test_triple_add_with_state_monad(self):
+ s1 = "*2"
+ w = lambda a: a * 2
+ f = lambda a: State(lambda s: (w(a), s.append(s1) or s))
+ k1 = KleisliArrowChoice(state_return, f)
+
+ s2 = "-9"
+ y = lambda a: a - 9
+ h = lambda a: State(lambda s: (y(a), s.append(s2) or s))
+ k2 = KleisliArrowChoice(state_return, h)
+
+ arrow = k1 + k2
+
+ value = 19
+ left_state = KleisliArrow.runKleisli(arrow, Left(value))
+ left = State.runState(left_state, [])
+ left_target = (Left(w(value)), [s1])
+ self.assertEquals(left_target, left)
+
+ right_state = KleisliArrow.runKleisli(arrow, Right(value))
+ right = State.runState(right_state, [])
+ right_target = (Right(y(value)), [s2])
+ self.assertEquals(right_target, right)
+
+
+ def test_triple_pipe_with_maybe_monad(self):
+ value = 11
+ f = lambda x: x * 9
+ k1 = KleisliArrowChoice(just_return, lambda a: Just(f(a)))
+
+ h = lambda x: x - 9
+ k2 = KleisliArrowChoice(just_return, lambda a: Just(h(a)))
+
+ arrow = k1 | k2
+
+ left = KleisliArrow.runKleisli(arrow, Left(value))
+ left_target = Just(f(value))
+ self.assertEquals(left_target, left)
+
+ right = KleisliArrow.runKleisli(arrow, Right(value))
+ right_target = Just(h(value))
+ self.assertEquals(right_target, right)
+
+
+ def test_triple_pipe_with_state_monad(self):
+ s1 = "*2"
+ w = lambda a: a * 2
+ f = lambda a: State(lambda s: (w(a), s.append(s1) or s))
+ k1 = KleisliArrowChoice(state_return, f)
+
+ s2 = "-9"
+ y = lambda a: a - 9
+ h = lambda a: State(lambda s: (y(a), s.append(s2) or s))
+ k2 = KleisliArrowChoice(state_return, h)
+
+ arrow = k1 | k2
+
+ value = 19
+ left_state = KleisliArrow.runKleisli(arrow, Left(value))
+ left = State.runState(left_state, [])
+ left_target = (w(value), [s1])
+ self.assertEquals(left_target, left)
+
+ right_state = KleisliArrow.runKleisli(arrow, Right(value))
+ right = State.runState(right_state, [])
+ right_target = (y(value), [s2])
+ self.assertEquals(right_target, right)