turtle_operations/model/
helpers.rs

1use algar::{m, Monad, Monoid, ResultT, StateT, Writer};
2
3use super::{
4    turtle::Turtle,
5    turtle_api::{self, TurtleError},
6};
7
8pub fn lift_op<'a, A: 'a>(
9    op_fun: impl Fn(Turtle, A) -> Turtle + 'static,
10) -> impl FnOnce(A) -> StateT<'a, Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>>
11{
12    move |p: A| {
13        StateT::new(move |s| {
14            ResultT::lift(Writer::new(
15                ((), op_fun(s, p)),
16                <String as Monoid>::mempty(),
17            ))
18        })
19    }
20}
21
22pub fn lift_validation<'a, A: 'a>(
23    validate_fun: impl Fn(String) -> Result<A, TurtleError>,
24) -> impl Fn(&str) -> StateT<'a, Turtle, ResultT<Writer<Result<(A, Turtle), TurtleError>, String>>>
25{
26    move |p: &str| {
27        StateT::<'a, Turtle, ResultT<Writer<Result<(A, Turtle), TurtleError>, String>>>::lift(
28            ResultT::new(Writer::new(
29                validate_fun(p.to_string()),
30                <String as Monoid>::mempty(),
31            )),
32        )
33    }
34}
35
36pub fn log_info(
37    l: String,
38) -> StateT<'static, Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>> {
39    StateT::<Turtle, ResultT<Writer<Result<(), TurtleError>, String>>>::lift(ResultT::lift(
40        Writer::<Turtle, _>::tell(String::from(l)),
41    ))
42}
43
44pub fn move_turtle(
45    d: &str,
46) -> StateT<Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>> {
47    let validate_distance = lift_validation(turtle_api::validate_distance);
48    let do_move = lift_op(Turtle::r#move);
49
50    m! {
51        log_info(format!("moving {}\n", d));
52        distance <- validate_distance(d);
53        do_move(distance)
54    }
55}
56
57pub fn turn_turtle(
58    a: &str,
59) -> StateT<Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>> {
60    let validate_angle = lift_validation(turtle_api::validate_angle);
61    let do_turn = lift_op(Turtle::turn);
62
63    m! {
64        log_info(format!("turning {}\n", a));
65        angle <- validate_angle(a);
66        do_turn(angle)
67    }
68}
69
70pub fn set_turtle_color(
71    c: &str,
72) -> StateT<Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>> {
73    let validate_pen_color = lift_validation(turtle_api::validate_pen_color);
74    let do_set_pen_color = lift_op(Turtle::set_pen_color);
75
76    m! {
77        log_info(format!("coloring pen to  {}\n", c));
78        color <- validate_pen_color(c);
79        do_set_pen_color(color)
80    }
81}
82
83pub fn run(
84    computation: StateT<Turtle, ResultT<Writer<Result<((), Turtle), TurtleError>, String>>>,
85    t: Turtle,
86) -> (Result<((), Turtle), TurtleError>, String) {
87    Writer::execute(ResultT::execute(StateT::execute(computation, t)))
88}