Skip to content

Instantly share code, notes, and snippets.

@louthy
Created March 27, 2020 20:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save louthy/17a9f3d0747db1b9ceb6028231838479 to your computer and use it in GitHub Desktop.
Save louthy/17a9f3d0747db1b9ceb6028231838479 to your computer and use it in GitHub Desktop.
using Echo;
using LanguageExt;
using static LanguageExt.Prelude;
using static Echo.Process;
using System;
namespace StackOverflow2
{
class Program
{
static void Main(string[] args)
{
var s1 = Student.New("Joe Bloggs", 24);
var s2 = Student.New("John Doe", 22);
var s3 = Student.New("Jane Doe", 21);
var t1 = Teacher.New("Richard Smith", 56);
var t2 = Teacher.New("Paul Louth", 44);
ProcessConfig.initialise();
var db = spawn<Database, DatabaseMsg>("db", DatabaseActor.Setup, DatabaseActor.Inbox);
tell(db, AddStudent.New(s1));
tell(db, AddStudent.New(s2));
tell(db, AddStudent.New(s3));
tell(db, AddTeacher.New(t1));
tell(db, AddTeacher.New(t2));
tell(db, AssignStudentToTeacher.New(s1, t1));
tell(db, AssignStudentToTeacher.New(s2, t1));
tell(db, AssignStudentToTeacher.New(s3, t2));
ask<Set<Teacher>>(db, FindStudentTeachers.New(s1)).Iter(Console.WriteLine);
ask<Set<Teacher>>(db, FindStudentTeachers.New(s2)).Iter(Console.WriteLine);
ask<Set<Teacher>>(db, FindStudentTeachers.New(s3)).Iter(Console.WriteLine);
ask<Set<Student>>(db, FindTeacherStudents.New(t1)).Iter(Console.WriteLine);
ask<Set<Student>>(db, FindTeacherStudents.New(t2)).Iter(Console.WriteLine);
tell(db, RemoveTeacher.New(t2));
ask<Set<Student>>(db, FindGhostStudents.New()).Iter(Console.WriteLine);
tell(db, RemoveStudent.New(s1));
ask<Set<Student>>(db, FindTeacherStudents.New(t1)).Iter(Console.WriteLine);
tell(db, RemoveStudent.New(s2));
ask<Set<Student>>(db, FindTeacherStudents.New(t1)).Iter(Console.WriteLine);
}
}
[Record]
public partial class Student
{
public readonly string Name;
public readonly int Age;
}
[Record]
public partial class Teacher
{
public readonly string Name;
public readonly int Age;
}
[Record]
public partial class Database
{
public static readonly Database Empty = new Database(default, default, default, default);
public readonly Map<Teacher, Set<Student>> TeacherStudents;
public readonly Map<Student, Set<Teacher>> StudentTeachers;
public readonly Set<Student> Students;
public readonly Set<Teacher> Teachers;
public Database AddTeacher(Teacher teacher) =>
With(Teachers: Teachers.Add(teacher),
TeacherStudents: TeacherStudents.Add(teacher, default));
public Database AddStudent(Student student) =>
With(Students: Students.Add(student),
StudentTeachers: StudentTeachers.Add(student, default));
public Database AssignStudentToTeacher(Student student, Teacher teacher) =>
With(StudentTeachers: StudentTeachers.SetItem(student, Some: ts => ts.AddOrUpdate(teacher)),
TeacherStudents: TeacherStudents.SetItem(teacher, Some: ss => ss.AddOrUpdate(student)));
public Database UnAssignStudentFromTeacher(Student student, Teacher teacher) =>
With(StudentTeachers: StudentTeachers.SetItem(student, Some: ts => ts.Remove(teacher)),
TeacherStudents: TeacherStudents.SetItem(teacher, Some: ss => ss.Remove(student)));
public Database RemoveTeacher(Teacher teacher) =>
With(Teachers: Teachers.Remove(teacher),
TeacherStudents: TeacherStudents.Remove(teacher),
StudentTeachers: StudentTeachers.Map(ts => ts.Remove(teacher)));
public Database RemoveStudent(Student student) =>
With(Students: Students.Remove(student),
StudentTeachers: StudentTeachers.Remove(student),
TeacherStudents: TeacherStudents.Map(ss => ss.Remove(student)));
public Option<Teacher> FindTeacher(string name, int age) =>
Teachers.Find(new Teacher(name, age));
public Option<Student> FindStudent(string name, int age) =>
Students.Find(new Student(name, age));
public Set<Student> FindTeacherStudents(Teacher teacher) =>
TeacherStudents
.Find(teacher)
.IfNone(Set<Student>());
public Set<Teacher> FindStudentTeachers(Student student) =>
StudentTeachers
.Find(student)
.IfNone(Set<Teacher>());
public Set<Student> FindGhostStudents() =>
toSet(StudentTeachers.Filter(teachers => teachers.IsEmpty).Keys);
}
[Union]
public interface DatabaseMsg
{
DatabaseMsg AddTeacher(Teacher teacher);
DatabaseMsg AddStudent(Student student);
DatabaseMsg AssignStudentToTeacher(Student student, Teacher teacher);
DatabaseMsg UnAssignStudentFromTeacher(Student student, Teacher teacher);
DatabaseMsg RemoveTeacher(Teacher teacher);
DatabaseMsg RemoveStudent(Student student);
DatabaseMsg FindTeacher(string name, int age);
DatabaseMsg FindStudent(string name, int age);
DatabaseMsg FindTeacherStudents(Teacher teacher);
DatabaseMsg FindStudentTeachers(Student student);
DatabaseMsg FindGhostStudents();
}
public static class DatabaseActor
{
public static Database Setup() =>
Database.Empty;
public static Database Inbox(Database state, DatabaseMsg msg) =>
msg switch
{
AddTeacher (var teacher) => state.AddTeacher(teacher),
AddStudent (var student) => state.AddStudent(student),
AssignStudentToTeacher (var student, var teacher) => state.AssignStudentToTeacher(student, teacher),
UnAssignStudentFromTeacher (var student, var teacher) => state.UnAssignStudentFromTeacher(student, teacher),
RemoveTeacher (var teacher) => state.RemoveTeacher(teacher),
RemoveStudent (var student) => state.RemoveStudent(student),
FindTeacher (var name, var age) => constant(state, reply(state.FindTeacher(name, age))),
FindStudent (var name, var age) => constant(state, reply(state.FindStudent(name, age))),
FindTeacherStudents (var teacher) => constant(state, reply(state.FindTeacherStudents(teacher))),
FindStudentTeachers (var student) => constant(state, reply(state.FindStudentTeachers(student))),
FindGhostStudents _ => constant(state, reply(state.FindGhostStudents())),
_ => state
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment