Monads/Maybe monad: Difference between revisions

Added FreeBASIC
(Added FreeBASIC)
 
(10 intermediate revisions by 5 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,217 ⟶ 1,353:
 
=={{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">
Line 1,233 ⟶ 1,374:
}
Operator "=" (z as maybe) {
if z.havevalue xor .havevalue then
Push z.[val]=.[val]
push false
else
Push z.[val]=.[val]
end if
}
Function unit() {
Line 1,247 ⟶ 1,392:
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)
Line 1,272 ⟶ 1,420:
k=each(SetA)
While K
m1=none.unit(array(Kk)) // pick element k^
m2=m1.bind(decrement).bind(triple)
m3=maybe(m2)
Line 1,281 ⟶ 1,429:
}
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}}
Line 1,419 ⟶ 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,436 ⟶ 1,654:
 
T = TypeVar("T")
U = TypeVar("U")
 
 
Line 1,445 ⟶ 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,457 ⟶ 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,471 ⟶ 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,894 ⟶ 2,114:
{{trans|Go}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="ecmascriptwren">import "./fmt" for Fmt
 
class Maybe {
Line 1,923 ⟶ 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,136

edits