Skip to content

Instantly share code, notes, and snippets.

@edreyer
Created October 10, 2019 04:37
Show Gist options
  • Save edreyer/6cbcfd8a4cf4d1e76a4f3da89e88c356 to your computer and use it in GitHub Desktop.
Save edreyer/6cbcfd8a4cf4d1e76a4f3da89e88c356 to your computer and use it in GitHub Desktop.
State Monad: Imperative to Functional
package techtalk;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import io.vavr.collection.HashMap;
import io.vavr.collection.Map;
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
import static com.jnape.palatable.lambda.functor.builtin.State.state;
public class ImperativeToFunctionalState {
static Double getPrice(String name) {
switch (name) {
case "carg": return 30.0;
case "goog": return 1200.0;
}
return 10.0;
}
public static class Imperative {
static Tuple2<Double, Map<String, Double>> buy(String name, Double amount, Map<String, Double> portfolio) {
final var purchased = amount / getPrice(name);
final var owned = portfolio.getOrElse(name, 0D);
return tuple(purchased, portfolio.put(name, owned + purchased));
}
static Tuple2<Double, Map<String, Double>> sell(String name, Double quantity, Map<String, Double> portfolio) {
final var revenue = quantity * getPrice(name);
final var owned = portfolio.getOrElse(name, 0D);
return tuple(revenue, portfolio.put(name, owned - quantity));
}
static Double get(String name, Map<String, Double> portfolio) {
return portfolio.getOrElse(name, 0D);
}
static Tuple2<Tuple2<Double, Double>, Map<String, Double>> move(String from, String to, Map<String, Double> portfolio) {
final var originallyOwned = get(from, portfolio);
Tuple2<Double, Map<String, Double>> sold = sell(from, originallyOwned, portfolio);
final var revenue = sold._1();
final var newPortfolio = sold._2();
Tuple2<Double, Map<String, Double>> bought = buy(to, revenue, newPortfolio);
final var purchased = bought._1();
final var veryNewPortfolio = bought._2();
return tuple(tuple(originallyOwned, purchased), veryNewPortfolio);
}
}
public static class Functional {
interface Transaction<A> extends Fn1<Map<String, Double>, Tuple2<A, Map<String, Double>>> {}
static Fn2<String, Double, Transaction<Double>> buyFn = (name, amount) ->
(Map<String, Double> portfolio) -> {
final var purchased = amount / getPrice(name);
final var owned = portfolio.getOrElse(name, 0D);
return tuple(purchased, portfolio.put(name, owned + purchased));
};
static Fn2<String, Double, Transaction<Double>> sellFn = (name, quantity) ->
(Map<String, Double> portfolio) -> {
final var revenue = quantity * getPrice(name);
final var owned = portfolio.getOrElse(name, 0D);
return tuple(revenue, portfolio.put(name, owned - quantity));
};
static Fn1<String, Transaction<Double>> getFn = (name) ->
(Map<String, Double> portfolio) -> tuple(portfolio.getOrElse(name, 0D), portfolio);
static Fn2<String, String, Transaction<Tuple2<Double, Double>>> moveFn = (from, to) ->
portfolio -> state(getFn.apply(from))
.flatMap(originallyOwned -> state(sellFn.apply(from, originallyOwned))
.flatMap(revenue -> state(buyFn.apply(to, revenue))
.fmap(purchased -> tuple(originallyOwned, purchased))))
.run(portfolio);
public static void main(String[] args) {
Transaction<Tuple2<Double, Double>> moveGoogToCarg = moveFn.apply("goog", "carg");
Map portfolio = HashMap.of("carg", 10.0, "goog", 100.0);
Tuple2 result = moveGoogToCarg.apply(portfolio);
System.out.println(result._1());
System.out.println(result._2());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment