Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ R.add(date(1,2,3), date(1,2,3)) # float('nan)
- [ ] andThen
- [x] 0.1.2 any
- [ ] anyPass
- [ ] ap
- [x] ap
- [ ] aperture
- [x] 0.1.2 append
- [ ] apply
Expand Down
1 change: 1 addition & 0 deletions ramda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .always import always
from .And import And
from .any import any
from .ap import ap
from .append import append
from .binary import binary
from .clone import clone
Expand Down
19 changes: 19 additions & 0 deletions ramda/ap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from .map import map
from .private._concat import _concat
from .private._curry2 import _curry2
from .private._helper import getAttribute
from .private._isFunction import _isFunction
from .private._reduce import _reduce


def inner_ap(applyF, applyX):
if _isFunction(getAttribute(applyX, 'fantasy-land/ap')):
return getAttribute(applyX, 'fantasy-land/ap')(applyF)
if _isFunction(getAttribute(applyF, 'ap')):
return getAttribute(applyF, 'ap')(applyX)
if _isFunction(applyF):
return lambda x: applyF(x)(applyX(x))
return _reduce(lambda acc, f: _concat(acc, map(f, applyX)), [], applyF)


ap = _curry2(inner_ap)
19 changes: 19 additions & 0 deletions test/helpers/Id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import ramda as R
from ramda.private._helper import getAttribute


def Id(value):
return {
'@@type': 'ramda/Id',
'fantasy-land/equals': lambda other: other is not None and getAttribute(other, '@@type') == 'ramda/Id' and R.equals(getAttribute(other, 'value'), value),
'fantasy-land/concat': lambda id: Id(R.concat(value, getAttribute(id, 'value'))),
'fantasy-land/map': lambda f: Id(f(value)),
'fantasy-land/ap': lambda id: Id(getAttribute(id, 'value')(value)),
'fantasy-land/chain': lambda f: f(value),
'fantasy-land/reduce': lambda f, x: f(x, value),
'fantasy-land/traverse': lambda f, of: R.map(Id, f(value)),
'sequence': lambda of: R.map(Id, value),
'constructor': {'fantasy-land/of': Id},
'toString': lambda: 'Id(' + R.toString(value) + ')',
'value': value
}
37 changes: 26 additions & 11 deletions test/test_ap.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@

import unittest
from test.helpers.Id import Id

import ramda as R

"""
https://github.com/ramda/ramda/blob/master/test/ap.js
"""

mult2 = R.multiply(2)
plus3 = R.add(3)


class TestAp(unittest.TestCase):
def test_returns_an_array_of_tuples(self):
a = [1, 2, 3]
b = [100, 200, 300]
self.assertEqual([[1, 100], [2, 200], [3, 300]], R.zip(a, b))

def test_returns_a_list_as_long_as_the_shorter_of_the_lists_input(self):
a = [1, 2, 3]
b = [100, 200, 300, 400]
c = [10, 20]
self.assertEqual([[1, 100], [2, 200], [3, 300]], R.zip(a, b))
self.assertEqual([[1, 10], [2, 20]], R.zip(a, c))
def test_interprets_list_a_as_an_applicative(self):
self.assertEqual([2, 4, 6, 4, 5, 6], R.ap([mult2, plus3])([1, 2, 3]))

def test_interprets_arrow_r_as_an_applicative(self):
def f(r): return lambda a: r + a
def g(r): return r * 2
h = R.ap(f, g)
# (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
# f <*> g = \x -> f x (g x)
self.assertEqual(10 + (10 * 2), h(10))
self.assertEqual(10 + (10 * 2), R.ap(R.add)(g)(10))

def test_dispatches_to_the_first_passed_object_ap_method_when_values_is_a_non_array(self):
obj = {'ap': lambda n: 'called ap with ' + str(n)}
self.assertEqual(obj['ap'](10), R.ap(obj, 10))

def test_works_with_fantasy_land_ap(self):
applyX = Id(10)
applyF = {'value': lambda x: x * 2}
res = R.ap(applyF, applyX)
self.assertEqual(20, res['value'])
self.assertEqual('ramda/Id', res['@@type'])

if __name__ == '__main__':
unittest.main()