Closed toburger closed 3 years ago
Thanks for the write-up, @toburger. This is fantastic.
I made a decision when starting the library to consider the constraint, variable, and domain types generic despite only implementing them for integers to begin with. This may have made more sense if I ever came back to implement more types, but I've lived with the base classes since then.
I like the proof of concept you have developed. If you'd allow, I could include this as an example solution, and reference in the README.md that it's possible to use Decider for F# as well as C#? (with credit to yourself, of course)
Of course, feel free to use my code as an example! :relaxed:
I have a very simple example which seems a bit childish but I think it explains very well a sample domain space where such CPS are very useful:
True story:
This is the solution of a homework the son of a friend had to solve during homeschooling and he (the father) asked a couple of his (not necessary developer) friends on how to solve the following problem as a formula:
Given a kickboard has three rolls and a city roller has two rolls we want to know how many kickboards and how many city rollers are parked.
We know two things:
Now being a developer I wanted to solve it programmatically, so here we go! 😄
open Decider.Csp.Integer
open Decider.Csp.BaseTypes
let solve rolls rollers =
let (==) left right = ExpressionInteger.(=)(left, right)
let expr i = ExpressionInteger(i)
let kickboards = VariableInteger("kickboards", 0, rollers)
let cityrollers = VariableInteger("cityrollers", 0, rollers)
let constraints: IConstraint list = [
ConstraintInteger(kickboards + cityrollers == expr rollers)
ConstraintInteger(kickboards * expr 3 + cityrollers * expr 2 == expr rolls)
]
let variables: IVariable<int> list = [
kickboards
cityrollers
]
let state = StateInteger(variables, constraints)
match state.Search() with
| StateOperationResult.Solved ->
Some {| Kickboards = kickboards.Value
Cityrollers = cityrollers.Value |}
| _ ->
None
solve 37 15
// val it : {| Cityrollers: int; Kickboards: int |} option =
// Some { Cityrollers = 8
// Kickboards = 7 }
Thanks for this, Tobias. I'm appreciative for sharing and for your time. You can see the above example in the following commit https://github.com/lifebeyondfife/Decider/commit/88622380a77f80f375b0456773b7cbe5e4476516
I've added a copyright notice in the file for your work, and an acknowledgement to @toburger in the README.md. Happy to accept a PR if you want to make my tweaking less messy / more authentically F#.
Hi, I'm very interested in logic programming and found some interesting implementations in different programming languages. I wanted to use a CSP solver on dotnet and as my primary language is F# I wanted to try it out in a F# script and evolve it then into a DSL that fits my needs.
This is the (1:1) translated script from the readme written in F#:
I had to introduce two helper functions:
==
which compares two expressions (F# is very strict and the standard F# equation=
cannot be diverted and requires to return a bool)expr
function, which converts an integer into an expression (F# does not support implicit conversions)The explicit type hints (
IConstraint list
,IVariable<int> list
) are not something a F# developer is used to deal with often but necessary, as the list cannot infer the common base class. But this inconvenience can be easily solved by either introduce some helper functions or introduce computation expressions that help declare the constraints and the variables.Note that this is a very naive translation from the C# code into F#. But I can imagine that out of this plumbing code could emerge a much friendlier DSL. :relaxed:
This is NOT a complaint about anything! It is merely intended to help the interested F# developer to getting started with this library. Thanks for this library!