diff --git a/package.json b/package.json index 7badb81e..1b91c01d 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ }, "devDependencies": { "eslint": "^3.17.1", - "purescript-psa": "^0.5.0-rc.1", - "pulp": "^10.0.4", + "purescript-psa": "^0.5.1", + "pulp": "^11.0.0", "rimraf": "^2.6.1" } } diff --git a/src/Control/Semigroupoid.js b/src/Control/Semigroupoid.js new file mode 100644 index 00000000..54f77899 --- /dev/null +++ b/src/Control/Semigroupoid.js @@ -0,0 +1,31 @@ +"use strict"; + +// https://medium.com/@safareli/stack-safe-function-composition-85d61feee37e +var runComposition = function(composition, x) { + var root = composition; + var val = x; + var stack = []; + for (;;) { + if (root._0 !== undefined){ + stack.push(root._1); + root = root._0; + } else { + val = root(val); + if (stack.length === 0) { + return val; + } + root = stack.shift(); + } + } +}; + +exports.functionCompose = function(f) { + return function(g) { + var res = function composition(x) { + return runComposition(composition, x); + }; + res._0 = g; + res._1 = f; + return res; + }; +}; diff --git a/src/Control/Semigroupoid.purs b/src/Control/Semigroupoid.purs index 729e1bbe..cdb85455 100644 --- a/src/Control/Semigroupoid.purs +++ b/src/Control/Semigroupoid.purs @@ -13,7 +13,9 @@ class Semigroupoid a where compose :: forall b c d. a c d -> a b c -> a b d instance semigroupoidFn :: Semigroupoid (->) where - compose f g x = f (g x) + compose = functionCompose + +foreign import functionCompose :: forall b c d. (c -> d) -> (b -> c) -> (b -> d) infixr 9 compose as <<< diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 983f5b47..5bf1f5b3 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -6,11 +6,21 @@ type AlmostEff = Unit -> Unit main :: AlmostEff main = do + functionComposition testNumberShow show testOrderings testOrdUtils testIntDegree +functionComposition :: AlmostEff +functionComposition = + assert + ("composition is stack safe") + (composeGo (_ + 1) id 0 0 == 100000) + +composeGo :: forall x a. Semigroupoid x => x a a -> x a a -> Int -> x a a +composeGo f acc n = if n == 100000 then acc else composeGo f (compose acc f) (n + 1) + foreign import testNumberShow :: (Number -> String) -> AlmostEff foreign import throwErr :: String -> AlmostEff