我已经开始在C#中建立一个函数式编程库,这在某种程度上受到了scalaz和Scala中的函数式编程的启发。
我希望得到一些关于Monad实现和评论的反馈。
请理解这是在C#和.NET中实现的,它们不支持类型分类和更高的索引。
这里是我到目前为止能够用开发出来的东西创建的一个示例演示。
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
namespace Sharper.Tests
{
internal class Student
{
public int Id{ get; set; }
public string Name{ get; set; }
}
internal class Score
{
public int StudentId{ get; set; }
public string Name{ get; set; }
public Decimal Result{ get; set; }
}
internal class ScoreServer
{
public ScoreServer()
{
students = new Dictionary<int, Student>();
scores = new Dictionary<int, List<Score>>();
students.Add(1, new Student{ Id = 1, Name = "Blair" });
students.Add(2, new Student{ Id = 2, Name = "Esther" });
scores.Add(1, new List<Score> {
new Score{ StudentId = 1, Name = "Maths", Result = 76 },
new Score{ StudentId = 1, Name = "English", Result = 56 },
new Score{ StudentId = 1, Name = "Science", Result = 67 }
});
scores.Add(2, new List<Score> {
new Score{ StudentId = 2, Name = "Maths", Result = 87 },
new Score{ StudentId = 2, Name = "English", Result = 72 },
new Score{ StudentId = 2, Name = "Science", Result = 59 }
});
}
public IO<String> GetStudentScoreFor(int studentId, string classname)
{
var studentT = GetStudentById(studentId).OptionT();
var studentNameT = studentT.Map(x => x.Name)
.OrElse(new Some<string>(studentId.ToString()));
var matchedScoreT = from student in studentT
from score in GetClassScoreByStudent(student.ToOption(), classname).OptionT()
select String.Format("Student: {0} Recieved {1} for {2}", student.Name, score.Name, score.Result);
var result = from name in studentNameT
from text in matchedScoreT.Map(score => score)
.OrElse(String.Format("Student {0} has not record for {1}", name, classname)
.ToOption())
select text;
return result.GetValueOrDefault(String.Empty);
}
public IO<Option<Student>> GetStudentById(int studentId)
{
return new IO<Option<Student>>(
() => {
Thread.Sleep(TimeSpan.FromSeconds(1.5)); // Simulate work
return students.SafeGet(studentId);
}
);
}
public IO<Option<Score>> GetClassScoreByStudent(Option<Student> student, string @class)
{
return new IO<Option<Score>>(
() => {
Thread.Sleep(TimeSpan.FromSeconds(1)); // Simulate work
return student.FlatMap(x => scores.SafeGet(x.Id)
.FlatMap(y => y.FirstOrDefault(z => z.Name == @class)
.ToOption()));
}
);
}
private Dictionary<int,Student> students{ get; set; }
private Dictionary<int, List<Score>> scores { get; set; }
}
[TestFixture]
public class OptionIODemoTests
{
[Test]
public void Testing_ScoreServer1()
{
var server = new ScoreServer();
var result = server.GetStudentScoreFor(1, "Maths").PerformUnsafeIO();
Assert.AreEqual(String.Format("Student: {0} Recieved {1} for {2}", "Blair", "Maths", 76), result);
}
[Test]
public void Testing_ScoreServer2()
{
var server = new ScoreServer();
var result = server.GetStudentScoreFor(1, "Mathematics").PerformUnsafeIO();
Assert.AreEqual(String.Format("Student {0} has not record for {1}", "Blair", "Mathematics"), result);
}
[Test]
public void Testing_ScoreServer3()
{
var server = new ScoreServer();
var result = server.GetStudentScoreFor(3, "Mathematics").PerformUnsafeIO();
Assert.AreEqual(String.Format("Student {0} has not record for {1}", "3", "Mathematics"), result);
}
}
}主要项目站点是这里。
发布于 2015-06-29 21:38:45
首先,这个Dictionary吸引了我的眼球:
students = new Dictionary<int, Student>();
students.Add(1, new Student{ Id = 1, Name = "Blair" });
students.Add(2, new Student{ Id = 2, Name = "Esther" });那么,您有一个字典,其中键已经包含在ID中,如果值是?为什么不把它变成一个普通的Dictionary<int, string>呢?如果保证键无论如何不会重复,您可以为简单起见设置一个List<Student>。
然而,从这个角度来看,似乎我们必须为每个学生保留一组Scores,而您通过保留两个列表来做到这一点。我会把这些组合成一个单子,一个Student,一个Id,Name,和一个List of Scores,然后,你可以把学生和他们的成绩放在一起。然而,这在允许复制Ids方面存在困难,因此也许Dictionary是这里最好的选择,即使Id在关键和价值上都是如此。
Testing_ScoreServer1()的描述性不是很强。我必须阅读测试才能弄清楚它到底是什么测试。稍后,当您进行使测试失败的更改时,您如何在不阅读代码的情况下知道什么是实际失败的?我会给它起一个描述性很强的名字,我可以从失败的测试列表中分辨出失败的原因。
新分数{ StudentId = 1,名称=“数学”,结果= 76 },新分数{ StudentId = 1,Name = "English",结果= 56 },新分数{ StudentId = 1,Name = "Science",结果= 67 }
在测试中使用值76,以及使用值"Blair"。如果你决定不喜欢76这个数字,然后把它改成75呢?那会打破你的测试。您应该考虑将这个值设置在一个地方作为一个变量,因此您只需要在一个地方更改它的值。也许你可以有一个List的学生,你从数据和使用您的所有考试?
https://codereview.stackexchange.com/questions/94330
复制相似问题