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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+