Created
January 3, 2022 19:10
-
-
Save olexale/568ae37ac956ffb53dac1eda96edf5e6 to your computer and use it in GitHub Desktop.
Sample for the "Dart Functors, Applicatives, And Monads In Pictures" article
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void main() { | |
// Functor | |
num plus3(num x) => x + 3; | |
print(Just(2).fmap(plus3)); // Just 5 | |
print(Nothing<num>().fmap(plus3)); | |
print([1,2,3].map((x) => x + 2)); // (3, 4, 5) | |
final foo = fmap((x) => x + 3, (x) => x + 2); | |
print(foo(10)); // 15 | |
// Aplicatives | |
print(Just(2).apply(Just((x) => x + 3))); // Just 5 | |
print([1, 2, 3].apply<int, int>([ | |
(x) => x * 2, | |
(x) => x + 3, | |
])); // [2, 4, 6, 4, 5, 6] | |
final curriedAddition = (num x) => (num y) => x + y; | |
// num Function(num) curriedAddition(num x) => (num y) => x + y; | |
final a = Just(3).fmap(curriedAddition); // Just<(int) => int> | |
// Just(5).fmap(a); // COMPILATION ERROR | |
print(Just(5).apply(a)); // Just 8 | |
final curriedTimes = (int x) => (int y) => x * y; | |
// num Function(num) curriedTimes(num x) => (num y) => x * y; | |
print(Just(5).apply(Just(3).fmap(curriedTimes))); // Just 15 | |
// Monads | |
Maybe<num> half(num a) => a % 2 == 0 ? Just(a / 2) : Nothing(); | |
print(Just(3).bind(half)); // Nothing | |
print(Just(4).bind(half)); // Just 2 | |
print(Nothing<num>().bind(half)); // Nothing | |
print(Just(20).bind(half).bind(half).bind(half)); // Nothing | |
} | |
// Helpers | |
typedef IntFunction = int Function(int); | |
IntFunction fmap(IntFunction f, IntFunction g) => (x) => f(g(x)); | |
extension ApplicativeList on List { | |
Iterable<U> apply<T, U>(List<U Function(T)> list) sync* { | |
for (final item in list) { | |
for (var i = 0; i < length; i++) { | |
yield item(this[i]); | |
} | |
} | |
} | |
} | |
// Maybe | |
abstract class Functor<T> { | |
Functor<U> fmap<U>(U Function(T) f); | |
} | |
abstract class Applicative<T> { | |
Applicative<U> apply<U>(Applicative<U Function(T)> f); | |
} | |
abstract class Monad<T> { | |
Monad<U> bind<U>(Monad<U> Function(T) f); | |
} | |
/// The Maybe type encapsulates an optional value. | |
/// Using Maybe is a good way to deal with errors or | |
/// exceptional cases without resorting to | |
/// drastic measures such as error. | |
abstract class Maybe<T> implements Functor<T>, Applicative<T>, Monad<T> {} | |
/// Represents a value of type Maybe that contains a value | |
/// (represented as Just a). | |
class Just<T> extends Maybe<T> { | |
Just(this.value); | |
final T value; | |
@override | |
Maybe<U> fmap<U>(U Function(T) f) => Just(f(value)); | |
@override | |
Maybe<U> apply<U>(covariant Maybe<U Function(T)> f) => | |
f.fmap((ff) => ff(value)) as Maybe<U>; | |
@override | |
Maybe<U> bind<U>(covariant Maybe<U> Function(T) f) => f(value); | |
@override | |
String toString() => 'Just $value'; | |
} | |
/// Represents an empty Maybe that holds nothing | |
/// (in which case it has the value of Nothing) | |
class Nothing<T> extends Maybe<T> { | |
@override | |
Maybe<U> fmap<U>(U Function(T) f) => Nothing(); | |
@override | |
Maybe<U> apply<U>(covariant Maybe<U Function(T)> f) => Nothing(); | |
@override | |
Maybe<U> bind<U>(covariant Maybe<U> Function(T) f) => Nothing(); | |
@override | |
String toString() => 'Nothing'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment