Есть вот такой код.
функция view каждый раз возвращает новый элемент управления, т.к. чистая.
Получается ФП не работает с Winforms? Нужны элементы ООП, чтобы избежать дикого оверхеда?
open System
open System.Windows.Forms
type Update<'Msg, 'Model> = 'Msg -> 'Model -> 'Model
type Dispatch<'Msg> = 'Msg -> obj -> EventArgs -> unit
type View<'Model, 'Msg> = 'Model -> Dispatch<'Msg> -> Control
type Program<'Model, 'Msg>(initialModel: 'Model, view: View<'Model, 'Msg>, update: Update<'Msg, 'Model>) =
let pump = Event<'Msg * 'Model>()
let evt = pump.Publish
let dispatch model msg _ _ = pump.Trigger(msg, model)
let form = new Form(Text = "OK")
do
evt.Add(fun (msg, model) ->
let newModel = update msg model
let newLayout = view newModel (dispatch newModel)
form.Controls.Clear()
form.Controls.Add(newLayout))
member __.Run() =
let initialLayout = view initialModel (dispatch initialModel)
form.Controls.Add(initialLayout)
form.ShowDialog()
type Model = int
let initialModel: Model = 0
type Msg =
| Increment
| Decrement
let update msg model =
match msg with
| Increment -> model + 1
| Decrement -> model - 1
let view model dispatch =
let clickCount = new Label(Text = sprintf "Clicked %d times" model)
let incrButton = new Button(Text = "+")
let incrClickHandler = EventHandler(dispatch Increment)
incrButton.Click.AddHandler(incrClickHandler)
let decrButton = new Button(Text = "-")
let decrClickHandler = EventHandler(dispatch Decrement)
decrButton.Click.AddHandler(decrClickHandler)
let layout = new FlowLayoutPanel(Dock = DockStyle.Fill)
layout.Controls.Add(clickCount)
layout.Controls.Add(incrButton)
layout.Controls.Add(decrButton)
layout :> Control
let runProgram model view update =
let main = Program(model, view, update)
main.Run()
runProgram initialModel view update
Здравствуйте, Разраб, Вы писали:
Р>Есть вот такой код. Р>функция view каждый раз возвращает новый элемент управления, т.к. чистая.
Здесь нет связи, можно представить чистую функцию, которая бы каждый раз возвращала один и тот же элемент. И грязную, которая бы возвращала каждый раз новый.
Р>Получается ФП не работает с Winforms? Нужны элементы ООП, чтобы избежать дикого оверхеда?
Получается, что что бы что-то утверждать, нужно формализовать понятие "ФП" и "работает". Если говорить именно о чистом ФП, то увы, с WinForms его скрестить будет сложно. Однако, F# преподносится гибридным и ФП в его рамках не обязано быть чистым. Компилятор ведь не требует чистоты функций.
о модели и элементах управления. Если мы не хотим пересоздавать часть формы при каждом изменении модели, то следует научиться менять элементы управления в соответствии с измененной моделью. Можно отдать чистой функции получение букета новых свойств для элементов управления, но все равно кому-то надо будет отдать изменение элементов в соотвествии с новыми свойствами. В лучших традициях ФП сделать вид что изменение состояния где-то под капотом.
Винформс не заведется без грязи. Собственно, стоит ли пытаться делать вид, что программа на ФП с Винформс вся чистая? Но даже если бы оно того и стоило, все равно пришлось бы написать грязный обновлятор Винформс, который бы подгибал элементы управления.
Здравствуйте, Разраб, Вы писали:
Р>Есть вот такой код. Р>функция view каждый раз возвращает новый элемент управления, т.к. чистая. Р>Получается ФП не работает с Winforms? Нужны элементы ООП, чтобы избежать дикого оверхеда?
Тут есть какой-то логический разрыв. Почему не работает-то?
Вот, в своё время в WinCtl32 какой-то из контролов часть свойств давал задавать только в момент создания. Соответствующая (вполне себе ООП-шная) обёртка в Delphi изящно обошла это ограничение — когда соответствующее свойство компонента менялось, под капотом на лету пересоздавался элемент управления. Я это хорошо помню, т.к. убил довольно много времени в пошаговой отладке, пытаясь понять, какой магией заменяется хэндл окна.
То есть,
а) ООП не означает обязательного сохранения элемента управления
б) создание нового элемента управления вовсе не так уж и плохо.
б1) как минимум, утечка памяти не является неотъемлемым свойством такого подхода.
Небольшим умственным усилием можно дойти и до следующей мысли:
в) ФП не означает обязательного пересоздания окна в терминах Windows.
То, что пользовательский код написан в терминах "замены элемента управления", не требует от инфраструктурного кода слепо делать именно это.
Можно динамически определять, можно ли обойтись "перенастройкой" существующего элемента управления, или всё же нужно прямо создавать прямо новый с нуля.
И уж если всё же потребовалось создать новый, никто не мешает инфраструктуре аккуратно прибить старый, избегая утечки памяти.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Тут есть какой-то логический разрыв. Почему не работает-то? S>Вот, в своё время в WinCtl32 какой-то из контролов часть свойств давал задавать только в момент создания. Соответствующая (вполне себе ООП-шная) обёртка в Delphi изящно обошла это ограничение — когда соответствующее свойство компонента менялось, под капотом на лету пересоздавался элемент управления. Я это хорошо помню, т.к. убил довольно много времени в пошаговой отладке, пытаясь понять, какой магией заменяется хэндл окна.
Да помню там для функции вызова нужно было передавать статическую функцию. А в Delphi все было на объектах. Они передавали ссылку на память динамически созданную в которой self записывался в регистр и вызывалась реальная функция объекта.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали: S> Да помню там для функции вызова нужно было передавать статическую функцию. А в Delphi все было на объектах. Они передавали ссылку на память динамически созданную в которой self записывался в регистр и вызывалась реальная функция объекта.
Очень, очень вряд ли. В более-менее все места WinAPI, где используются callback-и, есть возможность передать пользовательский параметр, и его передадут при обратном вызове.
Поэтому примерно все ООП-шные библиотеки туда передают адрес объекта. Callback обрабатывается статической функцией, которая достаёт из аргумента адрес объекта, и уже на нём вызывает виртуальный метод.
Но я, конечно же, всего знать не могу, потому было бы интересно на такое посмотреть. Особенно с учётом NX-флагов и прочей современщины.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>> Да помню там для функции вызова нужно было передавать статическую функцию. А в Delphi все было на объектах. Они передавали ссылку на память динамически созданную в которой self записывался в регистр и вызывалась реальная функция объекта. S>Очень, очень вряд ли. В более-менее все места WinAPI, где используются callback-и, есть возможность передать пользовательский параметр, и его передадут при обратном вызове. S>Поэтому примерно все ООП-шные библиотеки туда передают адрес объекта. Callback обрабатывается статической функцией, которая достаёт из аргумента адрес объекта, и уже на нём вызывает виртуальный метод. S>Но я, конечно же, всего знать не могу, потому было бы интересно на такое посмотреть. Особенно с учётом NX-флагов и прочей современщины.
Ну возможно и апи разные. Я то еще в конце 20 века это все анализировал. При чем они память создавали и как то её еще и помечали.
Они так же и для Com интерфейсов делали c корректировкой на реальные методы
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Разраб, Вы писали:
Р>Получается ФП не работает с Winforms? Нужны элементы ООП, чтобы избежать дикого оверхеда?
Вообще GUI и FP не особо хорошо работают вместе. GUI традиционно лучше ложится на ООП и событийную модель. GUI подразумевает изменяемое состояние. ФП — наоборот, трансформацию состояний чистыми функциями.
Чтобы было удобно программировать в ФП-стиле нужно и специально разрабатывать библиотеки. Можно создать GUI-либы для ФП стиля. Но смысла в этом не много. Зато ФП можно использовать в кишках.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.