Jump to content

Accumulator factory: Difference between revisions

add Mercury
(add Mercury)
Line 1,860:
{{out}}
<pre>8.3</pre>
 
=={{header|Mercury}}==
 
===Strict-adherence-to-the-task solution===
 
Deviations:
 
1. this doesn't work with "any numerical type" out of the box, but requires that users add numerical types to a typeclass.
 
2. this likely violates some hidden taste requirements of the task, as used by Paul Graham to dismiss Forth solutions. Certainly, this is not really an example of Mercury that anyone would want to use in a Mercury project.
 
<lang Mercury>:- module accum.
:- interface.
 
:- typeclass addable(T) where [
func T + T = T
].
 
:- impure func gen(T) = (impure (func(T)) = T) <= addable(T).
 
:- implementation.
:- import_module bt_array, univ, int.
 
:- mutable(states, bt_array(univ), make_empty_array(0), ground, [untrailed]).
 
gen(N) = F :-
some [!S] (
semipure get_states(!:S),
size(!.S, Size),
resize(!.S, 0, Size + 1, univ(N), !:S),
impure set_states(!.S)
),
F = (impure (func(Add)) = M :-
some [!SF] (
semipure get_states(!:SF),
!.SF ^ elem(Size) = U,
det_univ_to_type(U, M0),
M = M0 + Add,
!SF ^ elem(Size) := univ(M),
impure set_states(!.SF)
)).</lang>
 
As used:
 
<lang Mercury>:- module accumuser.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module accum, list, string, int, float.
 
:- instance addable(int) where [
A + B = int.(A + B)
].
 
:- instance addable(float) where [
A + B = float.(A + B)
].
 
:- pragma promise_pure main/2.
main(!IO) :-
impure F = accum.gen(1),
impure N1 = impure_apply(F, 1),
impure N2 = impure_apply(F, 1),
impure G = accum.gen(500.0),
impure R1 = impure_apply(G, -10.0),
impure R2 = impure_apply(G, -50.0),
io.format("%d, %d\n", [i(N1), i(N2)], !IO),
io.format("%.0f, %.0f\n", [f(R1), f(R2)], !IO).</lang>
 
{{out}}
<pre>
2, 3
490, 440
</pre>
 
===Realistic solution===
 
Deviations:
 
1. This still requires addition of numeric types to a typeclass, for a generic +
 
2. This doesn't return a closure with mutable state, but the state itself, which the caller can thread through rules that apply to them.
 
<lang Mercury>:- module accum2.
:- interface.
 
:- typeclass addable(T) where [
func T + T = T
].
 
:- type accum(T).
 
% init(N) = Acc
% Return an accumulator with initial value of N
%
:- func init(T) = accum(T)
<= addable(T).
 
% bump(By, N, !Acc)
% Add By to accumulator !Acc, yielding the next number as N
%
:- pred bump(T::in, T::out, accum(T)::in, accum(T)::out) is det
<= addable(T).
 
:- implementation.
 
:- type accum(T) == T.
 
init(N) = N.
 
bump(X, N, N0, N) :-
N = X + N0.</lang>
 
As used, with the same output:
 
<lang Mercury>:- module accumuser2.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module accum2, list, string, int, float.
 
:- instance addable(int) where [
A + B = int.(A + B)
].
 
:- instance addable(float) where [
A + B = float.(A + B)
].
 
main(!IO) :-
some [!A1] (
!:A1 = accum2.init(1),
accum2.bump(1, N1, !A1),
accum2.bump(1, N2, !.A1, _)
),
some [!A2] (
!:A2 = accum2.init(500.0),
accum2.bump(-10.0, R1, !A2),
accum2.bump(-50.0, R2, !.A2, _)
),
io.format("%d, %d\n", [i(N1), i(N2)], !IO),
io.format("%.0f, %.0f\n", [f(R1), f(R2)], !IO).</lang>
 
=={{header|Nemerle}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.