diff --git a/appveyor.yml b/appveyor.yml index 08ad15c..787c08d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ init: environment: matrix: - - solution: Semester4/NetworkModel/NetworkModel.sln + - solution: Semester4/Interpreter/Interpreter.sln before_build: - nuget restore %solution% diff --git a/semester4/Interpreter/Interpreter.sln b/semester4/Interpreter/Interpreter.sln new file mode 100644 index 0000000..09b7c2f --- /dev/null +++ b/semester4/Interpreter/Interpreter.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Interpreter", "Interpreter\Interpreter.fsproj", "{F4AC6C26-010E-4A43-9A7E-DE86E607064B}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "InterpreterTests", "InterpreterTests\InterpreterTests.fsproj", "{B0759521-85A7-4058-A22F-DAC2B0BC2EAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F4AC6C26-010E-4A43-9A7E-DE86E607064B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4AC6C26-010E-4A43-9A7E-DE86E607064B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4AC6C26-010E-4A43-9A7E-DE86E607064B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4AC6C26-010E-4A43-9A7E-DE86E607064B}.Release|Any CPU.Build.0 = Release|Any CPU + {B0759521-85A7-4058-A22F-DAC2B0BC2EAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0759521-85A7-4058-A22F-DAC2B0BC2EAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0759521-85A7-4058-A22F-DAC2B0BC2EAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0759521-85A7-4058-A22F-DAC2B0BC2EAE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/semester4/Interpreter/Interpreter/Interpreter.fs b/semester4/Interpreter/Interpreter/Interpreter.fs new file mode 100644 index 0000000..006f7a8 --- /dev/null +++ b/semester4/Interpreter/Interpreter/Interpreter.fs @@ -0,0 +1,54 @@ +module Interpreter + +/// Лямбда-терм, бывает трёх видов +type Term = + | Variable of char + | Abstraction of char * Term + | Application of Term * Term + +/// Свободна переменная в выражении или нет +let rec isFree expression variable = + match expression with + | Variable var -> var = variable + | Abstraction (var, term) -> var <> variable && isFree term variable + | Application (left, right) -> isFree left variable || isFree right variable + +/// Замена переменной в выражении +let rec substitution oldVariable newVariable expression = + let vars = [ 'a' .. 'z' ] + match expression with + | Variable var when var = oldVariable -> newVariable + | Variable _ -> expression + | Abstraction (var, _) when var = oldVariable -> expression + | Abstraction (var, term) when not <| isFree newVariable var -> + Abstraction(var, substitution oldVariable newVariable term) + | Abstraction (var, term) -> + let newSymbol = + vars + |> List.filter (not << isFree newVariable) + |> List.head + + Abstraction + (newSymbol, + substitution oldVariable newVariable + <| substitution var (Variable newSymbol) term) + | Application (left, right) -> + Application(substitution oldVariable newVariable left, substitution oldVariable newVariable right) + +/// Бета-редукция выражения +let betaReduction (term: Term) = + let rec betaReductionRec term = + match term with + | Variable var -> Variable(var) + | Abstraction (var, term) -> Abstraction(var, betaReductionRec <| term) + | Application (Abstraction (var, leftTerm), rightTerm) -> + leftTerm + |> substitution var rightTerm + |> betaReductionRec + | Application (left, right) -> + let leftReduce = betaReductionRec left + match leftReduce with + | Abstraction (_) -> Application(leftReduce, right) |> betaReductionRec + | _ -> Application(leftReduce, betaReductionRec right) + + betaReductionRec term diff --git a/semester4/Interpreter/Interpreter/Interpreter.fsproj b/semester4/Interpreter/Interpreter/Interpreter.fsproj new file mode 100644 index 0000000..877612d --- /dev/null +++ b/semester4/Interpreter/Interpreter/Interpreter.fsproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.1 + + + + + + + diff --git a/semester4/Interpreter/InterpreterTests/InterpreterTest.fs b/semester4/Interpreter/InterpreterTests/InterpreterTest.fs new file mode 100644 index 0000000..3b6c493 --- /dev/null +++ b/semester4/Interpreter/InterpreterTests/InterpreterTest.fs @@ -0,0 +1,44 @@ +module InterpreterTests + +open NUnit.Framework +open FsUnit +open Interpreter + +[] +let ``simple variable test`` () = + Variable('x') + |> betaReduction + |> should equal (Variable('x')) + +[] +let ``simple abstraction test`` () = + Abstraction('x', Variable('x')) + |> betaReduction + |> should equal (Abstraction('x', Variable('x'))) + +[] +let ``simple application test`` () = + Application(Variable('x'), Variable('y')) + |> betaReduction + |> should equal (Application(Variable('x'), Variable('y'))) + +// (λx.x y) +[] +let ``simple test`` () = + Application(Abstraction('x', Variable('x')), Variable('y')) + |> betaReduction + |> should equal (Variable('y')) + +// λx.(x y) z +[] +let ``simple test two`` () = + Application(Abstraction('x', Application(Variable('x'), Variable('y'))), Variable('z')) + |> betaReduction + |> should equal (Application(Variable('z'), Variable('y'))) + +// (λx.y z) (λa.(a z) b) +[] +let ``simple test three`` () = + Application(Application(Abstraction('x', Variable('y')), Variable('z')), Application(Abstraction('a', Application(Variable('a'), Variable('z'))), Variable('b'))) + |> betaReduction + |> should equal (Application(Variable('y'), Application(Variable('b'), Variable('z')))) \ No newline at end of file diff --git a/semester4/Interpreter/InterpreterTests/InterpreterTests.fsproj b/semester4/Interpreter/InterpreterTests/InterpreterTests.fsproj new file mode 100644 index 0000000..8011ef6 --- /dev/null +++ b/semester4/Interpreter/InterpreterTests/InterpreterTests.fsproj @@ -0,0 +1,25 @@ + + + + netcoreapp3.1 + + true + true + + + + + + + + + + + + + + + + + +