Monads/Maybe monad: Difference between revisions

Added FreeBASIC
m (syntax highlighting fixup automation)
(Added FreeBASIC)
 
(18 intermediate revisions by 7 users not shown)
Line 305:
 
{missing value, missing value, missing value, missing value, 0.5, 0.0, -0.346573590279, -0.499999999999, -0.549306144333, -0.69314718056, -0.804718956217}</pre>
 
=={{header|ATS}}==
<syntaxhighlight lang="ats">
#include "share/atspre_staload.hats"
 
(* There are "Option" and "Option_vt" in the ATS2 prelude, but I shall
construct something anew. *)
 
datatype Maybe (a : t@ype+) =
| Nothing of ()
| Just of a
 
fn {a, b : t@ype}
bind_Maybe {u : bool}
(m : Maybe a,
f : a -<cloref1> Maybe b) : Maybe b =
case+ m of
| Nothing {a} () => Nothing {b} ()
| Just {a} x => f x
 
infixl 0 >>=
overload >>= with bind_Maybe
 
implement
main0 () =
let
val f : int -<cloref1> Maybe int =
lam i =<cloref1> if (i : int) < 0 then Nothing () else Just i
val g : int -<cloref1> Maybe string =
lam i =<cloref1> Just (tostring_val<int> i)
in
case+ Just 123 >>= f >>= g of
| Nothing () => println! ("Nothing ()")
| Just s => println! ("Just (\"", s : string, "\")");
case+ Just ~123 >>= f >>= g of
| Nothing () => println! ("Nothing ()")
| Just s => println! ("Just (\"", s : string, "\")")
end
</syntaxhighlight>
 
{{out}}
<pre>$ patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_GCBDW maybe_monad_ats.dats -lgc && ./a.out
Just ("123")
Nothing ()</pre>
 
=={{header|C}}==
Line 726 ⟶ 770:
→ ❌ (#f . 0)
</syntaxhighlight>
 
=={{header|FreeBASIC}}==
{{trans|Wren}}
<syntaxhighlight lang="vbnet">Type mmaybe
As Integer value
End Type
 
Function Bindf(m As mmaybe, f As Function(As mmaybe) As mmaybe) As mmaybe
Return f(m)
End Function
 
Function Unit(i As Integer) As mmaybe
Dim As mmaybe m
m.value = i
Return m
End Function
 
Function Decrement(mm As mmaybe) As mmaybe
Dim As mmaybe result
result.value = Iif(mm.value = 0, 0, mm.value - 1)
Return Unit(result.value)
End Function
 
Function Triple(mm As mmaybe) As mmaybe
Dim As mmaybe result
result.value = Iif(mm.value = 0, 0, 3 * mm.value)
Return Unit(result.value)
End Function
 
Dim As Integer values(3) = {3, 4, 0, 5}
Dim As Function(As mmaybe) As mmaybe Ptr decrementPtr = @Decrement
Dim As Function(As mmaybe) As mmaybe Ptr triplePtr = @Triple
 
For i As Integer = Lbound(values) To Ubound(values)
Dim As mmaybe m1 = Unit(values(i))
Dim As mmaybe m2 = Bindf(Bindf(m1, decrementPtr), triplePtr)
Dim As String s1 = Iif(m1.value = 0, "none", Str(m1.value))
Dim As String s2 = Iif(m2.value = 0, "none", Str(m2.value))
Print Using "\ \ -> \ \"; s1; s2
Next i
 
Sleep</syntaxhighlight>
{{out}}
<pre> 3 -> 6
4 -> 9
none -> none
5 -> 12</pre>
 
=={{header|F_Sharp|F#}}==
Line 946 ⟶ 1,037:
│_.│
└──┘</syntaxhighlight>
 
=={{header|Java}}==
Java has a built-in generic "Maybe" monad in form of the Optional<T> class.
 
The class has static methods, "of" and "ofNullable", which act as the unit function
for wrapping nullable and non-nullable values respectively.
 
The class instance method, "flatMap", acts as the bind function.
<syntaxhighlight lang="java">
import java.util.Optional;
 
public final class MonadMaybe {
 
public static void main(String[] aArgs) {
System.out.println(doubler(5).flatMap(MonadMaybe::stringify).get());
System.out.println(doubler(2).flatMap(MonadMaybe::stringifyNullable).get());
Optional<String> option = doubler(0).flatMap(MonadMaybe::stringifyNullable);
String result = option.isPresent() ? option.get() : "Result is Null";
System.out.println(result);
}
private static Optional<Integer> doubler(int aN) {
return Optional.of(2 * aN);
}
 
private static Optional<String> stringify(int aN) {
return Optional.of("A".repeat(aN));
}
 
private static Optional<String> stringifyNullable(int aN) {
return ( aN > 0 ) ? Optional.ofNullable("A".repeat(aN)) : Optional.ofNullable(null);
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
AAAAAAAAAA
AAAA
Result is Null
</pre>
 
=={{header|JavaScript}}==
Line 1,214 ⟶ 1,350:
print("output:", table.concat(map(maybeToStr, outList), ", "), "\n")
</syntaxhighlight>
 
 
=={{header|M2000 Interpreter}}==
Revision 1. Now the operator "=" check if we have same status on haveValue for the two objects. If not we get the false in compare. Also the unit() function return "none" object from a an object not "none".
 
M2000 create objects (of type Group) either from a Class (which is a function), or from a copy of an object. The life of an object depends of the storing site, and the use of a pointer or not. Here all objects are one of two kinds: Objects like none, m1, m2, m3 and m5 are destruct at the exit of the module. Object on the SetA like none and none.unit() (which is a copy of none), destruct when last pointer (here SetA) deleted, and for this example, because SetA is local variable, the delete happen at the exit of current module. The m object which used in Bind() and Unit() function, and the g object are all objects which life end at the exit of those function, although these functions return a pointer to a copy of the m object, and check an internal field which make it "float". A float object is something different from an object holding by a pointer. M2000 always "expand" a float object when we place it to a variable (as a copy, or if the variable hold another object - always as group else we get error 0 - as a merge of these). So when we pick a "float" object from array, we get a copy. M2000 can use pointer to groups. The second list show how we can use pointers to groups. Pointers can be one of two types: A real pointes (here we use real pointers), or a weak pointer. The -> operator in a ->m (or =pointer(m)) where m hold a group (not a pointer) return a weak pointer (invalid if actual variable not exist). Here we use ->(m) which make m a float group and then change it to a pointer to float group (same as =pointer((m))). A pointer(none) return a real pointer if none is a pointer to group, or a weak pointer if it isn't a pointer. A pointer to group is a group, not an address. A pointer() return the Null pointer (which is a group of type Null). The Null group (user object in M2000), has a type that cannot inherit to other classes, also in a group merge with null we don't merge Null type. Merging is another way to produce groups from two or more other types, using objects (not classes).
 
===== Without using pointers =====
 
<syntaxhighlight lang="m2000 interpreter">
Class maybe {
private:
variant [val]="none"
boolean haveValue
public:
property val {
value // val return the [val] value
}
function bind(f) {
m=This // we can read private because bind is function of same class as m
if m.haveValue Then m.[val]=f(m.[val])
=m // copy (not pointer)
}
Operator "=" (z as maybe) {
if z.havevalue xor .havevalue then
push false
else
Push z.[val]=.[val]
end if
}
Function unit() {
variant k
if match("G") then // so we can read maybe class
read g as maybe // fail if not maybe class
if g.havevalue then push g.val
end if
Read ? k
m=This
if not type$(k)="Empty" then
integer v=k ' fail if k can't convert to integer
m.[val]=v
m.haveValue=true
else // so now we can produce "none" from an object which isn't "none"
m.[val]="none"
m.haveValue=false
end if
=m // copy (not pointer)
}
class:
// after class: all are temporary for the constuction phase
// module with class name is the contructor
// the object constracted before enter this module
// but we can change it. So we return a new one.
module maybe {
// so the constructor is the same as the .unit
// ![] pick argument list and place to unit()
// optionally we can skip the call if we have empty argument list
if not empty then
this=.unit(![])
end if
}
}
none=maybe()
decrement =lambda (x as integer)->x-1%
triple =lambda (x as integer)->x*3%
variant emptyvariant
// 3 and 4 are double, 5 is integer type
SetA=(3,4,none,5%, emptyvariant, none.unit())
k=each(SetA)
While K
m1=none.unit(array(k)) // pick element k^
m2=m1.bind(decrement).bind(triple)
m3=maybe(m2)
Print m1.val+" -> "+m2.val, m3=m2, m3.val
End While
Try ok {
m5=maybe("Hello")
}
Print not ok // true , "Hello" not accepted
</syntaxhighlight>
 
 
===== Using pointers =====
 
 
<syntaxhighlight lang="m2000 interpreter">
Class maybe {
private:
variant [val]="none"
boolean haveValue
public:
property val {
value // val return the [val] value
}
function bind(f) {
m=This // we can read private because bind is function of same class as m
if m.haveValue Then m.[val]=f(m.[val])
->(m) // pointer
}
Operator "=" (z as maybe) {
if z.havevalue xor .havevalue then
push false
else
Push z.[val]=.[val]
end if
}
Function unit() {
variant k
if match("G") then // so we can read maybe class
read g as maybe // fail if not maybe class
if g.havevalue then push g.val
end if
Read ? k
m=This
if not type$(k)="Empty" then
integer v=k ' fail if k can't convert to integer
m.[val]=v
m.haveValue=true
else // so now we can produce "none" from an object which isn't "none"
m.[val]="none"
m.haveValue=false
end if
->(m) // pointer
}
class:
module maybe {
if not empty then
this=.unit(![])
end if
}
}
none->maybe()
decrement =lambda (x as integer)->x-1%
triple =lambda (x as integer)->x*3%
variant emptyvariant
SetA=(3,4,none,5%, emptyvariant, none=>unit())
k=each(SetA)
document doc$
While k
m1=none=>unit(array(k)) // pick element k^
m2=m1=>bind(decrement)=>bind(triple)
m3=maybe(m2)
doc$=m1=>val+" -> "+m2=>val+" m2=m3 -> "+if$(m2=m3->"True", "False")+{
}
End While
Try ok {
m5=maybe("Hello")
}
Doc$= (not ok)+{
} // true , "Hello" not accepted
report doc$
clipboard doc$
</syntaxhighlight>
{{out}}
<pre>
3 -> 6 True 6
4 -> 9 True 9
none -> none True none
5 -> 12 True 12
none -> none True none
none -> none True none
True
</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import options,math,sugar,strformat
Line 1,340 ⟶ 1,640:
=={{header|Python}}==
 
The <code>Maybe</code> class constructor is effectively the <code>unit</code> function. Note that I've used <code>>></code> as the bind operator. Trying to chain <code>__irshift__</code> (<code>>>=</code>) would be a syntax error.
In this implementation, a <code>Maybe</code> type's constructor is effectively
the <code>unit</code> function. Note that I've used <code>>></code> as the bind
operator. Trying to chain <code>__irshift__</code> (<code>>>=</code>) would be a
syntax error.
 
<syntaxhighlight lang="python">"""A Maybe Monad. Requires Python >= 3.7 for type hints."""
"""A Maybe monad. Requires Python >= 3.7 for type hints."""
from __future__ import annotations
 
from typing import Any
from typing import Callable
from typing import Generic
Line 1,357 ⟶ 1,654:
 
T = TypeVar("T")
U = TypeVar("U")
 
 
Line 1,366 ⟶ 1,664:
self.value = value
 
def __rshift__(self, func: Callable[[Optional[T]], Maybe[AnyU]]) -> Maybe[U]:
return self.bind(func)
 
def bind(self, func: Callable[[Optional[T]], Maybe[AnyU]]) -> Maybe[AnyU]:
return func(self.value)
 
Line 1,378 ⟶ 1,676:
def plus_one(value: Optional[int]) -> Maybe[int]:
if value is not None:
return Maybe[int](value + 1)
return Maybe[int](None)
 
 
def currency(value: Optional[int]) -> Maybe[str]:
if value is not None:
return Maybe[str](f"${value}.00")
return Maybe[str](None)
 
 
Line 1,392 ⟶ 1,690:
 
for case in test_cases:
m_intresult = Maybe[int](case) >> plus_one >> currency
 
result = m_int >> plus_one >> currency
# or..
# result = m_intMaybe(case).bind(plus_one).bind(currency)
 
print(f"{str(case):<4} -> {result}")
</syntaxhighlight>
Line 1,646 ⟶ 1,945:
#=> #<Maybe @value=nil>
</syntaxhighlight>
 
=={{header|Rust}}==
The <code>Maybe</code> monad is called <code>Option<T></code> in Rust, it's widely used in the standard library and user code for functions that might not have sensible return values in certain cases but it's not an error/failure, such as a key doesn't exist for a hash map.
 
In addition, pure/just/return is <code>Some(T)</code> and bind is <code>Option::<T>::and_then(self, F)</code>.
 
<syntaxhighlight lang="Rust">
use std::collections::HashMap;
 
/// Returns the arithmetic square root of x, if it exists
fn arithmetic_square_root(x: u8) -> Option<u8> {
// the number of perfect squares for u8 is so low you can just fit the entire list in memory
let perfect_squares: HashMap<u8, u8> = HashMap::from([
(0, 0),
(1, 1),
(4, 2),
(9, 3),
(16, 4),
(25, 5),
(36, 6),
(49, 7),
(64, 8),
(81, 9),
(100, 10),
(121, 11),
(144, 12),
(169, 13),
(196, 14),
(225, 15),
]);
 
// `HashMap::<K, V>::get(&self, &Q)` also returns a `Option<&V>`, we then turn it to `Option<V>`
perfect_squares.get(&x).copied()
}
 
 
/// If x in base 10 is also a valid number when looking upside down, return a string slice for that
/// number upside down
fn upside_down_num(x: u8) -> Option<&'static str> {
match x {
0 => Some("0"),
1 => Some("1"),
6 => Some("9"),
8 => Some("8"),
9 => Some("6"),
10 => Some("01"),
11 => Some("11"),
16 => Some("91"),
_ => None
}
}
 
fn main() {
// if the number from 0 to 36 inclusive, is a perfect square and its square root is also a
// valid number when looking upside down, then we will get a Some containing the string slice,
// otherwise we get a None, indicating it's not a perfect square or the square root is not a
// valid number while looking upside down
(0..=36)
.map(|x| arithmetic_square_root(x).and_then(upside_down_num))
.enumerate()
.for_each(|(i, upside_down_square_root)|
println!("i = {i:02}, upside down square root = {upside_down_square_root:?}"));
}
</syntaxhighlight>
 
{{out}}
<pre>
i = 00, upside down square root = Some("0")
i = 01, upside down square root = Some("1")
i = 02, upside down square root = None
i = 03, upside down square root = None
i = 04, upside down square root = None
i = 05, upside down square root = None
i = 06, upside down square root = None
i = 07, upside down square root = None
i = 08, upside down square root = None
i = 09, upside down square root = None
i = 10, upside down square root = None
i = 11, upside down square root = None
i = 12, upside down square root = None
i = 13, upside down square root = None
i = 14, upside down square root = None
i = 15, upside down square root = None
i = 16, upside down square root = None
i = 17, upside down square root = None
i = 18, upside down square root = None
i = 19, upside down square root = None
i = 20, upside down square root = None
i = 21, upside down square root = None
i = 22, upside down square root = None
i = 23, upside down square root = None
i = 24, upside down square root = None
i = 25, upside down square root = None
i = 26, upside down square root = None
i = 27, upside down square root = None
i = 28, upside down square root = None
i = 29, upside down square root = None
i = 30, upside down square root = None
i = 31, upside down square root = None
i = 32, upside down square root = None
i = 33, upside down square root = None
i = 34, upside down square root = None
i = 35, upside down square root = None
i = 36, upside down square root = Some("9")
</pre>
 
=={{header|Swift}}==
{{works with|Swift|5}}
Swift has a "Maybe" type built in, called "Optional". I created a typealias so I could adhere to the naming convention. The unit function is also strictly unnecessary because Optional's constructor serves the same purpose. bind is also strictly unnecessary because Swift's Optional.flatmap function does the same thing.
 
I also created an infix operator analogous to Haskell's >>=. I can't use >>= itself because it already exists (left shift assignment) and I can't control the precedence.
 
<syntaxhighlight lang="Swift">
precedencegroup MonadPrecedence {
higherThan: BitwiseShiftPrecedence
associativity: left
}
 
infix operator >>-: MonadPrecedence // Monadic bind
 
typealias Maybe = Optional
 
extension Maybe
{
static func unit(_ x: Wrapped) -> Maybe<Wrapped>
{
return Maybe(x)
}
 
func bind<T>(_ f: (Wrapped) -> Maybe<T>) -> Maybe<T>
{
return self.flatMap(f)
}
 
static func >>- <U>(_ m: Optional<Wrapped>, _ f: (Wrapped) -> Maybe<U>) -> Maybe<U>
{
return m.flatMap(f)
}
}
 
func dividedBy2IfEven(_ x: Int) -> Maybe<Int>
{
x.isMultiple(of: 2) ? x / 2 : nil
}
 
func lineOfAs(_ x: Int) -> Maybe<String>
{
guard x >= 0 else { return nil }
let chars = Array<Character>(repeating: "A", count: x)
return String(chars)
}
 
print("\(Maybe.unit(6).bind(dividedBy2IfEven).bind(lineOfAs) ?? "nil")")
print("\(Maybe.unit(4) >>- dividedBy2IfEven >>- lineOfAs ?? "nil")")
print("\(Maybe.unit(3) >>- dividedBy2IfEven >>- lineOfAs ?? "nil")")
print("\(Maybe.unit(-4) >>- dividedBy2IfEven >>- lineOfAs ?? "nil")")
</syntaxhighlight>
 
{{out}}
<pre>
AAA
AA
nil
nil
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="ecmascriptwren">import "./fmt" for Fmt
 
class Maybe {
Line 1,679 ⟶ 2,143:
var s1 = (m1.value) ? "%(m1.value)" : "none"
var s2 = (m2.value) ? "%(m2.value)" : "none"
SystemFmt.print("%(Fmt.$4s -> $s(4", s1), s2) -> %(s2)")
}</syntaxhighlight>
 
2,122

edits