-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
319 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module Hw5.Calculator | ||
|
||
open System | ||
|
||
type CalculatorOperation = | ||
| Plus = 0 | ||
| Minus = 1 | ||
| Multiply = 2 | ||
| Divide = 3 | ||
|
||
[<Literal>] | ||
let plus = "+" | ||
|
||
[<Literal>] | ||
let minus = "-" | ||
|
||
[<Literal>] | ||
let multiply = "*" | ||
|
||
[<Literal>] | ||
let divide = "/" | ||
|
||
[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>] | ||
let inline calculate value1 operation value2: 'a = | ||
(NotImplementedException() |> raise) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="MaybeBuilder.fs" /> | ||
<Compile Include="Message.fs" /> | ||
<Compile Include="Calculator.fs" /> | ||
<Compile Include="Parser.fs" /> | ||
<Compile Include="Program.fs" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module Hw5.MaybeBuilder | ||
|
||
open System | ||
|
||
type MaybeBuilder() = | ||
member builder.Bind(a, f): Result<'e,'d> = | ||
(NotImplementedException() |> raise) | ||
member builder.Return x: Result<'a,'b> = | ||
(NotImplementedException() |> raise) | ||
let maybe = MaybeBuilder() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Hw5 | ||
|
||
type Message = | ||
| SuccessfulExecution = 0 | ||
| WrongArgLength = 1 | ||
| WrongArgFormat = 2 | ||
| WrongArgFormatOperation = 3 | ||
| DivideByZero = 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module Hw5.Parser | ||
|
||
open System | ||
open Hw5.Calculator | ||
|
||
let isArgLengthSupported (args:string[]): Result<'a,'b> = | ||
(NotImplementedException() |> raise) | ||
|
||
[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>] | ||
let inline isOperationSupported (arg1, operation, arg2): Result<('a * CalculatorOperation * 'b), Message> = | ||
(NotImplementedException() |> raise) | ||
|
||
let parseArgs (args: string[]): Result<('a * CalculatorOperation * 'b), Message> = | ||
(NotImplementedException() |> raise) | ||
|
||
[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>] | ||
let inline isDividingByZero (arg1, operation, arg2): Result<('a * CalculatorOperation * 'b), Message> = | ||
(NotImplementedException() |> raise) | ||
|
||
let parseCalcArguments (args: string[]): Result<'a, 'b> = | ||
(NotImplementedException() |> raise) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
open System | ||
|
||
(NotImplementedException() |> raise) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Домашняя работа №5 | ||
|
||
## Монадки | ||
|
||
*В Java-команду приходит программист и предлагает переписать все на Scala. Команда посовещавшись | ||
отвечает: “забирай свои монадки и проваливай отсюда…”* | ||
|
||
### Теория | ||
1. [Материалы лекции](https://docs.google.com/presentation/d/1wNLLm4mgdve8BnMIxaEajKHLV401-l_8PR0vg91UBqs/edit#slide=id.p100) | ||
2. [Сила композиции](https://habr.com/ru/company/jugru/blog/553028/) (монады) | ||
3. [Функторы, аппликативные функторы и монады в картинках, без картинок](https://habr.com/ru/post/183150/) | ||
4. [Understanding map and apply, Understanding bind, Using the core functions in practice](https://fsharpforfunandprofit.com/posts/elevated-world/) | ||
5. [Composition with an Either computation expression](https://blog.ploeh.dk/2016/03/21/composition-with-an-either-computation-expression/) | ||
6. [Железнодорожно-ориентированное программирование](https://habr.com/ru/post/339606/) ([расширенная версия с >=>](https://fsharpforfunandprofit.com/posts/recipe-part2/)) | ||
|
||
### Вопросы к семинару | ||
1. Выберите одно слово, заканчивающиеся на *-able* или *-емый/емая*, чтобы описать сущность монад | ||
2. Что общего у монадических типов Option, Seq, Task? Чем они отличаются? | ||
3. С помощью какой функции может быть выражена функциональная композиция для монадических типов? | ||
4. Как с помощью bind и return получить map? | ||
5. Как с помощью map и return получить bind? | ||
6. Как связаны побочные эффекты, ссылочная прозрачность и чистота функций? Почему в Haskell функции по-умолчанию чистые? | ||
7. Как сделать ранний возврат из функции в F# без использования исключений? | ||
|
||
### Практика | ||
1. Использовать [Result Computation Expression](https://fsharpforfunandprofit.com/posts/computation-expressions-intro/) для обработки ошибок калькулятора на F#. Программа не должна выбрасывать исключения. | ||
2. Добавить тесты на операции с типами int, float, double, decimal). Допустимо использовать несколько билдеров, inline-функций, дженерики вида ’ или ^ и другие возможности F#. Предпочтение следует отдать решениям с минимальным дублированием кода. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module Tests.Homework5.CalculatorTests | ||
|
||
open Hw5.Calculator | ||
open Microsoft.FSharp.Core | ||
open Tests.RunLogic.Attributes | ||
open Xunit | ||
|
||
let epsilon: decimal = 0.001m | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15, 5, CalculatorOperation.Plus, 20)>] | ||
[<InlineData(15, 5, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15, 5, CalculatorOperation.Multiply, 75)>] | ||
[<InlineData(15, 5, CalculatorOperation.Divide, 3)>] | ||
let ``+, -, *, / work return correct calculation results with ints`` (value1 : int, value2: int, operation, expectedValue : int) = | ||
//act | ||
let actual = calculate value1 operation value2 | ||
|
||
//assert | ||
Assert.Equal(expectedValue, actual) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``+, -, *, / work return correct calculation results with floats`` | ||
(value1 : float, value2: float, operation, expectedValue : float) = | ||
//act | ||
let actual = abs (expectedValue - calculate value1 operation value2) | ||
|
||
//assert | ||
Assert.True(actual |> decimal < epsilon) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``+, -, *, / work return correct calculation results with doubles`` | ||
(value1 : double, value2: double, operation, expectedValue : double) = | ||
//act | ||
let actual = abs (expectedValue - calculate value1 operation value2) | ||
|
||
//assert | ||
Assert.True(actual |> decimal < epsilon) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``+, -, *, / work return correct calculation results with decimals`` | ||
(value1 : decimal, value2: decimal, operation, expectedValue : decimal) = | ||
//act | ||
let actual = abs (expectedValue - calculate value1 operation value2) | ||
|
||
//assert | ||
Assert.True(actual < epsilon) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
module Tests.Homework5.ParserTests | ||
|
||
open System | ||
open Hw5 | ||
open Hw5.Calculator | ||
open Hw5.Parser | ||
open Microsoft.FSharp.Core | ||
open Tests.RunLogic.Attributes | ||
open Xunit | ||
|
||
let epsilon: decimal = 0.001m | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15, 5, CalculatorOperation.Plus, 20)>] | ||
[<InlineData(15, 5, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15, 5, CalculatorOperation.Multiply, 75)>] | ||
[<InlineData(15, 5, CalculatorOperation.Divide, 3)>] | ||
let ``ints parsed correctly`` (value1 : int, value2: int, operation, expectedValue : int) = | ||
//act | ||
let actual = Calculator.calculate value1 operation value2 | ||
|
||
//assert | ||
Assert.Equal(expectedValue, actual) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``floats parsed correctly`` (value1 : float, value2: float, operation, expectedValue : float) = | ||
//act | ||
let actual = (abs (expectedValue - Calculator.calculate value1 operation value2)) | ||
|
||
//assert | ||
Assert.True(actual |> decimal < epsilon) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``doubles parsed correctly`` (value1 : double, value2: double, operation, expectedValue : double) = | ||
//act | ||
let actual = (abs (expectedValue - Calculator.calculate value1 operation value2)) | ||
|
||
//assert | ||
Assert.True(actual |> decimal < epsilon) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Plus, 21.2)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Minus, 10)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Multiply, 87.36)>] | ||
[<InlineData(15.6, 5.6, CalculatorOperation.Divide, 2.7857)>] | ||
let ``decimals parsed correctly`` (value1 : decimal, value2: decimal, operation, expectedValue : decimal) = | ||
//act | ||
let actual = (abs (expectedValue - Calculator.calculate value1 operation value2)) | ||
|
||
//assert | ||
Assert.True(actual < epsilon) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData("15", "+", "5", 20)>] | ||
[<InlineData("15", "-", "5", 10)>] | ||
[<InlineData("15", "*", "5", 75)>] | ||
[<InlineData("15", "/", "5", 3)>] | ||
[<InlineData("15.6", "+", "5.6", 21.2)>] | ||
[<InlineData("15.6", "-", "5.6", 10)>] | ||
[<InlineData("15.6", "*", "5.6", 87.36)>] | ||
[<InlineData("15.6", "/", "5.6", 2.7857)>] | ||
let ``values parsed correctly`` (value1, operation, value2, expectedValue) = | ||
//arrange | ||
let values = [|value1;operation;value2|] | ||
|
||
//act | ||
let result = parseCalcArguments values | ||
|
||
//assert | ||
match result with | ||
| Ok resultOk -> | ||
match resultOk with | ||
| arg1, operation, arg2 -> Assert.True((abs (expectedValue - Calculator.calculate arg1 operation arg2)) |> decimal < epsilon) | ||
| Error e -> raise (InvalidOperationException(e)) | ||
|
||
[<HomeworkTheory(Homeworks.HomeWork5)>] | ||
[<InlineData("f", "+", "3")>] | ||
[<InlineData("3", "+", "f")>] | ||
[<InlineData("a", "+", "f")>] | ||
let ``Incorrect values return Error`` (value1, operation, value2) = | ||
//arrange | ||
let args = [|value1;operation;value2|] | ||
|
||
//act | ||
let result = parseCalcArguments args | ||
|
||
//assert | ||
match result with | ||
| Ok _ -> raise (InvalidOperationException("This test must always return Error Result Type")) | ||
| Error resultError -> Assert.Equal(resultError, Message.WrongArgFormat) | ||
|
||
[<Homework(Homeworks.HomeWork5)>] | ||
let ``Incorrect operations return Error`` () = | ||
//arrange | ||
let args = [|"3";".";"4"|] | ||
|
||
//act | ||
let result = parseCalcArguments args | ||
|
||
//assert | ||
match result with | ||
| Ok _ -> raise (InvalidOperationException("This test must always return Error Result Type")) | ||
| Error resultError -> Assert.Equal(resultError, Message.WrongArgFormatOperation) | ||
|
||
[<Homework(Homeworks.HomeWork5)>] | ||
let ``Incorrect argument count throws ArgumentException`` () = | ||
//arrange | ||
let args = [|"3";"+";"4";"5"|] | ||
|
||
//act | ||
let result = parseCalcArguments args | ||
|
||
//assert | ||
match result with | ||
| Ok _ -> raise (InvalidOperationException("This test must always return Error Result Type")) | ||
| Error resultError -> Assert.Equal(resultError, Message.WrongArgLength) | ||
|
||
[<Homework(Homeworks.HomeWork5)>] | ||
let ``any / 0 -> Error(Message.DivideByZero)`` () = | ||
//arrange | ||
let args = [|"3";"/";"0"|] | ||
|
||
//act | ||
let result = parseCalcArguments args | ||
|
||
//assert | ||
match result with | ||
| Ok _ -> raise (InvalidOperationException("This test must always return Error Result Type")) | ||
| Error resultError -> Assert.Equal(resultError, Message.DivideByZero) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters