Monads/List monad: Difference between revisions
m
→{{header|Wren}}: Changed to Wren S/H
m (→{{header|Wren}}: Changed to Wren S/H) |
|||
(7 intermediate revisions by 6 users not shown) | |||
Line 23:
We can use a list monad in AppleScript to express set comprehension for the Pythagorean triples, but the lack of nestable first class (and anonymous) functions means that the closure can only be achieved using script objects, which makes the idiom rather less direct and transparent. AppleScript is creaking at the seams here.
<
-- Monadic bind for lists is simply ConcatMap
Line 138:
end script
end if
end mReturn</
{{Out}}
<
=={{header|ATS}}==
<syntaxhighlight lang="ats">
#include "share/atspre_staload.hats"
(* I will use the list type of prelude/SATS/list.sats *)
#define NIL list_nil ()
#define :: list_cons
fn {a : t@ype}
unit_List (x : a) : list (a, 1) =
x :: NIL
fn {a, b : t@ype}
bind_List (m : List a,
f : a -<cloref1> List b) : List0 b =
let
fun
reversed_segments (m : List a,
accum : List0 (List b))
: List0 (List b) =
case+ m of
| NIL => accum
| hd :: tl => reversed_segments (tl, f hd :: accum)
fun
assemble_segments (segments : List (List b),
accum : List0 b)
: List0 b =
case+ segments of
| NIL => accum
| hd :: tl =>
let
prval () = lemma_list_param hd
val accum = list_append (hd, accum)
in
assemble_segments (tl, accum)
end
in
assemble_segments (reversed_segments (m, NIL), NIL)
end
infixl 0 >>=
overload >>= with bind_List
fn
intseq_List {n : nat}
(i0 : int,
n : int n) :<cloref1> list (int, n) =
let
implement
list_tabulate$fopr<int> j = i0 + j
in
list_vt2t (list_tabulate<int> n)
end
implement
main0 () =
let
val n = 25
val pythagorean_triples =
intseq_List (1, n) >>=
(lam i =>
(intseq_List (succ (i : int), n) >>=
(lam j =>
(intseq_List (succ (j : int), n) >>=
(lam k =>
let
val i = i : int
and j = j : int
and k = k : int
in
if (i * i) + (j * j) = (k * k) then
@(i, j, k) :: NIL
else
NIL
end)))))
fun
loop {n : nat}
.<n>.
(m : list (@(int, int, int), n)) : void =
case+ m of
| NIL => ()
| (@(a, b, c) :: tl) =>
begin
println! ("(", a, ",", b, ",", c, ")");
loop tl
end
in
loop pythagorean_triples
end
</syntaxhighlight>
{{out}}
We should get a list of some Pythagorean triples that start with some integer between 1 and 25, inclusive.
<pre>$ patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_GCBDW list_monad_ats.dats -lgc && ./a.out
(3,4,5)
(5,12,13)
(6,8,10)
(7,24,25)
(8,15,17)
(9,12,15)
(10,24,26)
(12,16,20)
(12,35,37)
(15,20,25)
(15,36,39)
(16,30,34)
(18,24,30)
(20,21,29)
(21,28,35)
(24,32,40)
(24,45,51)
</pre>
=={{header|C}}==
Line 150 ⟶ 269:
Still, the task example is constrained enough that we can provide an implementation like:
<
#include <stdlib.h>
Line 176 ⟶ 295:
int main() {
task(13);
}</
Which, from the command line, might look like:
<
13</
=={{header|C++}}==
<
#include <vector>
Line 291 ⟶ 409:
PrintTriples(pythagoreanTriples);
}
</syntaxhighlight>
{{out}}
<pre>
Line 317 ⟶ 435:
=={{header|Clojure}}==
<
(defn bind [coll f] (apply vector (mapcat f coll)))
(defn unit [val] (vector val))
Line 328 ⟶ 446:
(bind doubler)
(bind vecstr)) ; also evaluates to ["6" "8" "10"]
</syntaxhighlight>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{Trans|Go}}
<syntaxhighlight lang="delphi">
program List_monad;
Line 399 ⟶ 517:
Writeln(ml1.ToString, ' -> ', ml2.ToString);
readln;
end.</
{{out}}
<pre>[ 3, 4, 5] -> [ 8, 10, 12]</pre>
=={{header|EchoLisp}}==
Our monadic lists will take the form (List a b c ...), ie raw lists prefixed by the List symbol.
<
;; -> and ->> are the pipeline operators
;; (-> x f g h) = (h (g ( f x)))
Line 424 ⟶ 542:
(-> '(1 -2 3 -5) List.unit (List.bind List.cube) (List.bind List.tostr))
→ (List "1" "-8" "27" "-125")
</syntaxhighlight>
=={{header|F_Sharp|F#}}==
<
type ListMonad() =
member o.Bind( (m:'a list), (f: 'a -> 'b list) ) = List.concat( List.map f m )
Line 441 ⟶ 559:
printf "%A" (pyth_triples 100)
</syntaxhighlight>
The list monad is equivalent to [[List comprehensions]] which are built into F#:
<
// Monads/List monad . Nigel Galloway: March 8th., 2021
List.iter ((+) 1>>(*) 2>>printf "%d ") [3;4;5]; printfn "";;
Line 455 ⟶ 573:
let test n=match valid(Ok n) with Ok g->printfn "%d is valid" g|Error e->printfn "Error: %d %s" n e
[5..10]|>List.iter test
</syntaxhighlight>
{{out}}
<pre>
Line 470 ⟶ 588:
=={{header|Factor}}==
Factor comes with an implementation of Haskell-style monads in the <code>monads</code> vocabulary.
<
FROM: monads => do ;
{ 3 4 5 }
>>= [ 1 + array-monad return ] swap call
>>= [ 2 * array-monad return ] swap call .</
Or:
<
[ 1 + array-monad return ] bind
[ 2 * array-monad return ] bind .</
Or:
<
[ { 3 4 5 } ]
[ 1 + array-monad return ]
[ 2 * array-monad return ]
} do .</
{{out}}
<pre>
Line 494 ⟶ 612:
=={{header|FreeBASIC}}==
{{trans|Ring}}
<
Dim As String m2 = "["
Dim As Integer x, y ,z
Line 505 ⟶ 623:
m2 &= "]"
Print m2
Sleep</
{{out}}
<pre>[8, 10, 12]</pre>
Line 511 ⟶ 629:
=={{header|Go}}==
<
import "fmt"
Line 545 ⟶ 663:
ml2 := ml1.bind(increment).bind(double)
fmt.Printf("%v -> %v\n", ml1.value, ml2.value)
}</
{{out}}
Line 555 ⟶ 673:
Haskell has the built-in <code>Monad</code> type class, and the built-in list type already conforms to the <code>Monad</code> type class.
<
Or, written using <code>do</code> notation:
<
y <- return (x+1)
z <- return (y*2)
return z</
Or alternately:
<
let y = x+1
let z = y*2
return z</
Using the list monad to express set comprehension for Pythagorean triples:
<
pythagoreanTriples n =
[1 .. n] >>= (\x ->
Line 577 ⟶ 695:
if x^2 + y^2 == z^2 then return (x,y,z) else [])))
main = print $ pythagoreanTriples 25</
{{out}}
<pre>[(3,4,5),(5,12,13),(6,8,10),(7,24,25),(8,15,17),(9,12,15),(12,16,20),(15,20,25)]</pre>
Which can be written using <code>do</code> notation:
<
pythagoreanTriples n = do x <- [1 .. n]
y <- [x+1 .. n]
z <- [y+1 .. n]
if x^2 + y^2 == z^2 then return (x,y,z) else []</
Or directly as a list comprehension:
<
pythagoreanTriples n = [(x,y,z) | x <- [1 .. n], y <- [x+1 .. n], z <- [y+1 .. n], x^2 + y^2 == z^2]</
=={{header|J}}==
Line 598 ⟶ 716:
That said, here is an implementation which might be adequate for the current task description:
<
unit=: boxopen
m_num=: unit
m_str=: unit@":</
Task example:
<
┌─┐
│5│
└─┘</
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public final class MonadList {
public static void main(String[] aArgs) {
Monad<Integer> integers = Monad.unit(List.of( 2, 3, 4 ));
Monad<String> strings = integers.bind(MonadList::doubler).bind(MonadList::letters);
System.out.println(strings.getValue());
}
private static Monad<Integer> doubler(List<Integer> aList) {
return Monad.unit(aList.stream().map( i -> 2 * i ).toList());
}
private static Monad<String> letters(List<Integer> aList) {
return Monad.unit(aList.stream().map( i -> Character.toString((char) (64 + i)).repeat(i) ).toList());
}
}
final class Monad<T> {
public static <T> Monad<T> unit(List<T> aList) {
return new Monad<T>(aList);
}
public <U> Monad<U> bind(Function<List<T>, Monad<U>> aFunction) {
return aFunction.apply(list);
}
public List<T> getValue() {
return list;
}
private Monad(List<T> aList) {
list = new ArrayList<T>(aList);
}
private List<T> list;
}
</syntaxhighlight>
{{ out }}
<pre>
[DDDD, FFFFFF, HHHHHHHH]
</pre>
=={{header|Javascript}}==
<
Array.prototype.bind = function (func) {
return this.map(func).reduce(function (acc, a) { return acc.concat(a); });
Line 632 ⟶ 801:
[3,4,5].bind(listy_inc).bind(listy_doub); // [8, 10, 12]
</syntaxhighlight>
ES5 Example: Using the list monad to express set comprehension
<
// ENCODING A SET COMPREHENSION IN TERMS OF A LIST MONAD
Line 687 ⟶ 856:
}
})(25);</
{{Out}}
<pre>[[3, 4, 5], [5, 12, 13], [6, 8, 10], [7, 24, 25], [8, 15, 17], [9, 12, 15], [12, 16, 20], [15, 20, 25]]</pre>
=={{header|jq}}==
{{works with|jq}}
''Also works with gojq and fq'' modulo the proviso about "::"
In this entry, we adopt the approach described in the Wikipedia article on monads
at [https://en.wikipedia.org/wiki/Monad_(functional_programming)], specifically:
<pre>
"A monad can be created by defining a type constructor M and two operations:
return :: a -> M a (often also called unit), which receives a value of type a and wraps it into a monadic value of type M a,
and
bind :: (M a) -> (a -> M b) -> (M b)
which receives a function f over type a and can transform monadic values m a applying f to the unwrapped value a,
returning a monadic value M b"
</pre>
In the following, the monadic type `a` can be specified as any JSON
value, but for the List monad, it is just "List". Choosing a string has the advantage
that we can use jq's support for function names of the form
`Namespace::identifier` to give convenient names to the "return" and
"bind" functions for the List monad, namely `List::return` and
`List::bind`.
Since gojq does not currently support the definition of functions
with a Namespace prefix, the following would have to be adapted; one
possibility wold be to replace occurrences of `::` in function names
by `__`.
Notice that the "return" and "bind" wrappers for List (i.e., `List::return` and
`List::bind`) can be tailored to the List monad independently of the
wrapper definitions for other monads.
<syntaxhighlight lang=jq>
# Constructor:
def Monad($type; $value):
{class: "Monad", $type, $value};
# Is the input a monad of type $Type?
def is_monad($Type):
(type == "object")
and (.class == "Monad")
and (.type == $Type) ;
# input: a value consistent with the "List" monadic type (in practice, a JSON array)
# No checking is done here as the monadic type system is outside the scope of this entry.
def List::return:
Monad("List"; .);
def List::bind(f):
if is_monad("List")
then .value |= f
else error("List::bind error: monadic type of input is \(.type)")
end;
# Two illustrative operations on JSON arrays
def increment: map(. + 1);
def double: map(. * 2);
def ml1:
[3, 4, 5] | List::return;
def ml2:
ml1 | List::bind(increment) | List::bind(double);
"\(ml1.value) -> \(ml2.value)"
</syntaxhighlight>
{{output}}
<pre>
[3,4,5] -> [8,10,12]
</pre>
=={{header|Julia}}==
Julia uses the function bind for binding a channel to a task, but this can be imported and overloaded.
The |> syntax in Julia can also be used to chain functions taking one argument.
<
unit (generic function with 1 method)
Line 721 ⟶ 960:
8
10
</syntaxhighlight>
=={{header|Kotlin}}==
<
class MList<T : Any> private constructor(val value: List<T>) {
Line 742 ⟶ 981:
val fv = iv.bind(::doubler).bind(::letters)
println(fv.value)
}</
{{out}}
Line 750 ⟶ 989:
=={{header|Nim}}==
a natural use of a list-wrapped return value is when there can be more than one result from a function, for example square roots have a positive and negative solution, and the inverse sine function has multiple solutions we might be interested in.
<
func root(x:float):seq[float] = @[sqrt(x),-sqrt(x)]
func asin(x:float):seq[float] = @[arcsin(x),arcsin(x)+TAU,arcsin(x)-TAU]
Line 760 ⟶ 999:
input.map(f).concat
echo [0.5] --> root --> asin --> format </
{{out}}<pre>@["0.79", "7.07", "-5.50", "-0.79", "5.50", "-7.07"]</pre>
=={{header|OCaml}}==
Defining the list monad is fairly straightforward:
<
fun l f -> List.flatten (List.map f l)
let return x = [x]</
For convenience, the example will also use the following definitions:
<
let (let*) = bind (* let pruning for easy bind *)
let print_str_list l =
Format.printf "[%a]" (fun fmt -> Format.pp_print_list Format.pp_print_string fmt) l</
First example: increment and print
<
let hex x = return (Format.sprintf "%#x" x)
Line 796 ⟶ 1,035:
let* x = List.init 5 (fun x -> x) in
let* y = incr x in hex y
in print_str_list l</
Second example: pythegorean triplets
<
let pythegorean_triple n =
let x = List.init n (fun x -> x) in
Line 822 ⟶ 1,061:
let* y = List.init n (fun x -> x) in
let* z = List.init n (fun x -> x) in
if x*x + y*y = z*z then return (x,y,z) else []</
=={{header|Perl}}==
With the help of the CPAN module <code>Data::Monad</code>, we can work with list monads.
<
use feature 'say';
use Data::Monad::List;
Line 853 ⟶ 1,092:
for (@{shift @triples}) {
say keys %$_ if keys %$_;
}</
{{out}}
<pre>000
Line 869 ⟶ 1,108:
=={{header|Phix}}==
{{trans|Go}}
<!--<
<span style="color: #008080;">function</span> <span style="color: #000000;">bindf</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span>
Line 889 ⟶ 1,128:
<span style="color: #000000;">m2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bindf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bindf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">increment</span><span style="color: #0000FF;">),</span><span style="color: #000000;">double</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%v -> %v\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">m1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">m2</span><span style="color: #0000FF;">})</span>
<!--</
{{out}}
<pre>
Line 897 ⟶ 1,136:
=={{header|Python}}==
<syntaxhighlight lang="python">
"""A List Monad. Requires Python >= 3.7 for type hints."""
from __future__ import annotations
from itertools import chain
from typing import Callable
from typing import Iterable
Line 909 ⟶ 1,148:
T = TypeVar("T")
U = TypeVar("U")
Line 916 ⟶ 1,156:
return cls(value)
def bind(self, func: Callable[[T], MList[
return MList(chain.from_iterable(map(func, self)))
def __rshift__(self, func: Callable[[T], MList[
return self.bind(func)
if __name__ == "__main__":
# Chained int and string functions.
print(
MList([1, 99, 4])
Line 938 ⟶ 1,178:
)
# Cartesian product of [1..5] and [6..10].
print(
MList(range(1, 6)).bind(
Line 945 ⟶ 1,185:
)
# Pythagorean triples with elements between 1 and 25.
print(
MList(range(1, 26)).bind(
Line 957 ⟶ 1,197:
)
)
</syntaxhighlight>
{{out}}
Line 975 ⟶ 1,215:
Note that this also demonstrates how to use Racket's macro system to implement the do syntax.
<
(define (bind x f) (append-map f x))
Line 1,017 ⟶ 1,257:
(pythagorean-triples* 25)
;; => '((3 4 5) (5 12 13) (6 8 10) (8 15 17) (9 12 15) (12 16 20))</
=== With functional package ===
Line 1,023 ⟶ 1,263:
The [https://docs.racket-lang.org/functional/interfaces.html functional] package has already implemented the list monad.
<
(require data/monad
Line 1,038 ⟶ 1,278:
(pythagorean-triples 25)
;; => '((3 4 5) (5 12 13) (6 8 10) (8 15 17) (9 12 15) (12 16 20))</
=={{header|Raku}}==
Line 1,049 ⟶ 1,289:
The * in the bind blocks are typically referred to as "whatever"; whatever + 3 etc. The guillemot (») is the hyper operator; descend into the data structure and apply the following operator/function to each member.
<syntaxhighlight lang="raku"
multi bind ($item, &code) { $item.&code };
Line 1,055 ⟶ 1,295:
sub divisors (Int $int) { gather for 1 .. $int { .take if $int %% $_ } }
put (^10).&bind(* + 3).&bind(&divisors)».&bind(*.base: 2).join: "\n";</
{{out}}
Line 1,070 ⟶ 1,310:
=={{header|Ring}}==
<
# Project : Monads/List monad
Line 1,083 ⟶ 1,323:
str = str + "]"
see str + nl
</syntaxhighlight>
Output:
<pre>
Line 1,091 ⟶ 1,331:
=={{header|Ruby}}==
<
class Array
def bind(f)
Line 1,135 ⟶ 1,375:
[3,4,5].bind_comp(listy_doub, listy_inc) #=> [8, 10, 12]
</syntaxhighlight>
=={{header|Swift}}==
The unit/return function is provided by the constructor for a Swift array. I define a unit function simply to keep the terminology straight. Similarly, the flatmap function provides what we need for bind, but I define a bind function explicitly.
I also define an operator that is the same as bind but which makes chaining easier.
My two functions to use are one that retiurns the two number adjacent to the supplied Int and another that returns the square roots (as Double) of an Int if it is positive or an empty list, if it is negative.
<syntaxhighlight lang="Swift">
precedencegroup MonadPrecedence {
higherThan: BitwiseShiftPrecedence
associativity: left
}
infix operator >>-: MonadPrecedence // Monadic bind
extension Array
{
static func unit(_ x: Element) -> [Element]
{
return [x]
}
func bind<T>(_ f: (Element) -> [T]) -> [T]
{
return flatMap(f)
}
static func >>- <U>(_ m: [Element], _ f: (Element) -> [U]) -> [U]
{
return m.flatMap(f)
}
}
func adjacent(_ x: Int) -> [Int]
{
[x - 1, x + 1]
}
func squareRoots(_ x: Int) -> [Double]
{
guard x >= 0 else { return [] }
return [Double(x).squareRoot(), -(Double(x).squareRoot())]
}
print("\([Int].unit(8).bind(adjacent).bind(squareRoots))")
print("\([Int].unit(8) >>- adjacent >>- squareRoots)")
print("\([Int].unit(0) >>- adjacent >>- squareRoots)")
</syntaxhighlight>
{{out}}
<pre>
[2.6457513110645907, -2.6457513110645907, 3.0, -3.0]
[2.6457513110645907, -2.6457513110645907, 3.0, -3.0]
[1.0, -1.0]
</pre>
=={{header|uBasic/4tH}}==
{{trans|Ring}}
<syntaxhighlight lang="text">s := "[" : Push 5, 4, 3
Do While Used ()
Line 1,147 ⟶ 1,442:
Print Show (Set (s, Join (Clip (s, 2), "]")))
</syntaxhighlight>
{{out}}
<pre>
Line 1,157 ⟶ 1,452:
=={{header|Wren}}==
{{trans|Go}}
<
construct new(value) { _value = value }
Line 1,179 ⟶ 1,474:
var ml1 = Mlist.unit([3, 4, 5])
var ml2 = ml1.bind(increment).bind(double)
System.print("%(ml1.value) -> %(ml2.value)")</
{{out}}
Line 1,191 ⟶ 1,486:
{{trans|Ruby}}
Here we create a class to do Monad like things. Unlike Ruby, we can't augment the baked in List/Array object so this more verbose. Also unlike Ruby, we can directly compose as we are applying the composition to each element (vs the list-as-object).
<
fcn init(xs){ var list=vm.arglist }
fcn bind(f) { list=list.apply(f); self }
fcn toString{ list.toString() }
}</
<
str:="toString";
MList(3,4,5).bind(inc).bind(str).println(" == (4,5,6)");
Line 1,204 ⟶ 1,499:
comp:=Utils.Helpers.fcomp; // comp(f,g) == f.g == f(g(x))
MList(3,4,5).bind(comp(doub,inc)).println(" == (8,10,12)");</
{{out}}
<pre>
|