Something went wrong. Try again.
The Monad language. Dependent types, functional programming compiled with LLVM. Hobby project. monad-lang.org
dependent-types language compiler programming-language functional-programming
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195/// Optics Example — Lenses and Prisms in Monad////// Demonstrates creating lenses for struct fields, using view/set/over,/// and prisms for working with sum types.#![mote { name := "optics", deps := [init] }]use init::optics {Lens, Prism, lens, over, over_prism, preview, set, view}open Prism {mkPrism}// --- Domain types ---struct Address { street : String, city : String,}struct Person { name : String, age : I64, address : Address,}type Shape { circle (radius : F64), rectangle (w : F64) (h : F64),}open Shape {circle, rectangle}// --- Lenses for Person ---def get_name (p : Person) : String := match p { mk name _ _ => name }def set_name (n : String) (p : Person) : Person := match p { mk _ age addr => { name := n, age := age, address := addr } }def name_lens : Lens Person String := lens get_name set_namedef get_age (p : Person) : I64 := match p { mk _ age _ => age }def set_age (a : I64) (p : Person) : Person := match p { mk name _ addr => { name := name, age := a, address := addr } }def age_lens : Lens Person I64 := lens get_age set_agedef get_address (p : Person) : Address := match p { mk _ _ addr => addr }def set_address (a : Address) (p : Person) : Person := match p { mk name age _ => { name := name, age := age, address := a } }def address_lens : Lens Person Address := lens get_address set_address// --- Lenses for Address ---def get_street (a : Address) : String := match a { mk street _ => street }def set_street (s : String) (a : Address) : Address := match a { mk _ city => { street := s, city := city } }def street_lens : Lens Address String := lens get_street set_streetdef get_city (a : Address) : String := match a { mk _ city => city }def set_city (c : String) (a : Address) : Address := match a { mk street _ => { street := street, city := c } }pub def city_lens : Lens Address String := lens get_city set_city// --- Prism for Shape ---def shape_circle_preview (s : Shape) : Option F64 := match s { circle r => some r, rectangle _ _ => none }def circle_prism : Prism Shape F64 := Prism.mkPrism shape_circle_preview (fn r => circle r)def shape_rectangle_preview (s : Shape) : Option (Pair F64 F64) := match s { circle _ => none, rectangle w h => some (Pair.pair w h) }def shape_rectangle_review (dims : Pair F64 F64) : Shape := match dims { Pair.pair w h => rectangle w h }def rectangle_prism : Prism Shape (Pair F64 F64) := Prism.mkPrism shape_rectangle_preview shape_rectangle_review// --- Arithmetic helpers ---def add_one (x : I64) : I64 := x + 1def double_f (x : F64) : F64 := x * 2.0// --- Tests ---#[test]def test_basic_lens_view : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let n_val : String := view name_lens p in n_val == "Alice"#[test]def test_basic_lens_set_age : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let p2 : Person := set age_lens 31 p in let a_val : I64 := view age_lens p2 in a_val == 31#[test]def test_lens_over_age_keeps_name : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let p2 : Person := over age_lens add_one p in let n_val : String := view name_lens p2 in let a_val : I64 := view age_lens p2 in n_val == "Alice" && a_val == 31#[test]def test_lens_chained_set : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let p2 : Person := set name_lens "Bob" p in let p3 : Person := set age_lens 25 p2 in let n_val : String := view name_lens p3 in let a_val : I64 := view age_lens p3 in n_val == "Bob" && a_val == 25#[test]def test_lens_nested_address_street : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let p_addr : Address := view address_lens p in let s_val : String := view street_lens p_addr in s_val == "Main St"#[test]def test_lens_nested_address_update : Bool := let addr : Address := { street := "Main St", city := "Springfield" } in let p : Person := { name := "Alice", age := 30, address := addr } in let p_addr : Address := view address_lens p in let new_addr : Address := set street_lens "Oak Ave" p_addr in let p2 : Person := set address_lens new_addr p in let final_addr : Address := view address_lens p2 in let s_val : String := view street_lens final_addr in s_val == "Oak Ave"#[test]def test_prism_circle_double_radius : Bool := let s : Shape := circle 5.0 in let s2 : Shape := over_prism circle_prism double_f s in let val : Option F64 := preview circle_prism s2 in match val { none => false, some r => let r_val : F64 := r in r_val == 10.0 }#[test]def test_prism_rectangle_unchanged_by_circle_prism : Bool := let s : Shape := rectangle 10.0 20.0 in let s2 : Shape := over_prism circle_prism double_f s in match s2 { circle _ => false, rectangle w h => let w_val : F64 := w in let h_val : F64 := h in w_val == 10.0 && h_val == 20.0 }#[test]def test_prism_rectangle_preview_dimensions : Bool := let s : Shape := rectangle 4.0 7.0 in let val : Option (Pair F64 F64) := preview rectangle_prism s in match val { none => false, some dims => match dims { Pair.pair w h => let w_val : F64 := w in let h_val : F64 := h in w_val == 4.0 && h_val == 7.0 } }