Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local network graph is ready #8

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Conversation

viktoriia-fomina
Copy link
Owner

No description provided.

module LocalNetwork

open System
open System.Collections.Generic

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System.Collections.Generic в F# нетипичен, обычно встроенных структур данных достаточно (только они все немутабельные, так что System.Collections.Generic может быть полезен в плане производительности на некоторых задачах)

let numberOfComputers () = List.length computersCommunication

/// Random numbers sensors for computers. On every step check if the computer is infected.
let rndSensorValues = new List<Random>()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мм, а зачем Вам целый список генераторов случайных чисел? Обычно одного на всю программу вполне достаточно, но целый список генераторов --- это очень загадочно. Это же просто генератор случайных чисел, он просто возвращает следующее случайное число. Если сделать их два и у каждого вызвать Next, Вы получите два случайных числа --- точно так же, как если сделать один и у него дважды вызвать Next.

initRec (acc + 1)
initRec 0

do init |> ignore

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем тогда init что-то возвращает?


/// Checks if the current step infects computer.
let isInfectedThisStep vertex =
(probabilityOfInfection vertex).CompareTo(double(rndSensorValues.[vertex].Next(0, 100))) >= 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут бы и просто оператор сравнения подошёл, кажется

|> List.iter (fun x -> if not (infected.Contains x) && isInfectedThisStep x then newInfected.Add x)

/// Infects first computer.
let infectFirst =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мм, это не функция, а значение, вычисляющееся в момент создания объекта и далее не меняющееся. А называется как функция и используется, кажется, как функция

elif (infected.Count = numberOfComputers() || infected.TrueForAll(fun x -> not <| neighboursCanBeInfected x)) then infected
else
infected.ForEach(fun x -> tryInfectNeighbours x)
infected.AddRange(newInfected);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Точка с запятой не нужна. Ну и правда, это какой-то уж очень императивный код, куча мутабельного состояния и неочевидные зависимости по данным. Я бы newInfected просто возвращал и не делал полем.

elif (infected.Count = numberOfComputers () || infected.TrueForAll(fun x -> not <| neighboursCanBeInfected x)) then infected
else
infected.ForEach(fun x -> tryInfectNeighbours x)
infected.AddRange(newInfected)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут концептуально ничего не поменялось, это всё так же жутковато даже для кода на C#, а уж на F# так писать вообще нельзя без веских причин :)

Comment on lines 11 to 14
let mutable infected = new List<int>()

/// Infected this step.
let mutable newInfected = new List<int>()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Они mutable, но в них буквально нет ни одного присванивания. Зачем они mutable? Но я выше намекал, что их лучше вообще заменить на 'a list. Не настаиваю, но код не должен вызывать ощущения "что происходит?". Пока вызывает.

let mutable infected = []

/// Infected this step.
let mutable newInfected = []

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так нет, функциональный стиль --- это не когда у нас поле немутабельного типа, котрое по сути представляет собой глобальную переменную, его кто-то где-то внутри меняет, потом его надо не забыть сбросить в пустой список и т.д., функциональный стиль --- это когда у нас практически нет состояния и мы всё, что надо, просто возвращаем из функций или передаём как параметр, так что поток данных в программе в точности соответствует потоку исполнения. Тут можно было сделать так, чтобы tryInfectNeighbours выдавал список заражённых, а вместо List.iter(fun x -> tryInfectNeighbours x) infected (что само по себе не очень, правильно List.iter tryInfectNeighbours infected) сделать List.map и List.concat

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И мне кажется, как раз забыли сбросить newInfected :)

let tryInfectNeighbours vertex =
let tryInfectNeighboursRec vertex =
computersCommunication.[vertex]
|> List.iter (fun x -> if not (List.contains x infected) && isInfectedThisStep x then newInfected <- newInfected @ [x])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newInfected @ [x] или x :: newInfected?

Copy link

@yurii-litvinov yurii-litvinov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну да, как-то так. Зачтена

type LocalNetwork(computersCommunication: int list list, OSOfComputers: string list, probabilityInfectionForOS: float list) =

/// Number of computers in local network.
let numberOfComputers () = List.length computersCommunication

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это можно было сделать полем, ведь computersCommunication немутабельный, его длину можно сосчитать один раз и она не сможет измениться

infectAllRec []

/// Infects all the computers with virus. Returns infected computers.
member public this.Infected = infectAll

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тогда оно должно называться как что-то вроде "Infect"

if List.length infected = 0 then
printInf infected
infectAllRec (infectFirst () :: infected)
elif (List.length infected = numberOfComputers () || List.forall (fun x -> not (neighboursCanBeInfected x infected)) infected) then infected

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы сказал, что граф сети может быть несвязным или разбитым на изолированные области "незаражаемыми" компьютерами, а это условие тут вроде как не проверяется, так что зависнуть мы таки можем. Но ладно :)

/// Tries to infect all the vertexes that are connected with infected.
let tryInfectNeighboursOfInfected infected =
let rec tryInfectNeighboursOfInfectedRec infected leftVrtxs =
match leftVrtxs with

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пхнглуи вагх`нагл фхагн. Ну и имена у Вас в программе :)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ахахахха :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants