turtle_operations/model/
helpers.rs1use 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}