Skip to content

Local network graph is ready#8

Open
viktoriia-fomina wants to merge 16 commits into
masterfrom
LocalNetworkGraph
Open

Local network graph is ready#8
viktoriia-fomina wants to merge 16 commits into
masterfrom
LocalNetworkGraph

Conversation

@viktoriia-fomina
Copy link
Copy Markdown
Owner

No description provided.

module LocalNetwork

open System
open System.Collections.Generic
Copy link
Copy Markdown

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>()
Copy link
Copy Markdown

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
Copy link
Copy Markdown

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
Copy link
Copy Markdown

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 =
Copy link
Copy Markdown

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);
Copy link
Copy Markdown

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)
Copy link
Copy Markdown

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>()
Copy link
Copy Markdown

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 = []
Copy link
Copy Markdown

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

Copy link
Copy Markdown

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])
Copy link
Copy Markdown

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
Copy Markdown

@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
Copy link
Copy Markdown

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
Copy link
Copy Markdown

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
Copy link
Copy Markdown

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
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