F#, вычисление дистанции между узлами дерева
От: zverjuga Беларусь  
Дата: 22.07.19 21:29
Оценка: -1
приветствую. засел за изучение F#. язык и подход для меня новый, все переворачивается с ног на голову, потому прошу помощи. имеется следующий код

module Street

    type Paint =
        | FillColor of float
        | BorderColor of float
        | BorderWidth of float

    type Point =
        | Position of x:float * y:float
        | Description of string
        | Radius of float
        | Lanes of uint32

    type Street =
        | Node of Street * Point list * Street // back * points * right. street like tree
        | Empty

    let distance (pt1: Point) (pt2: Point) =
        let square x = x * x
        sqrt <| square (pt1.x - pt2.x) + square (pt1.y - pt2.y)


смысл следующий. тип Stree — это дорога, представленная в виде дерева. в самом простом случае это дерево имеет вид простого списка, без ответвлений, вот его и рассматриваю.
тип Street хранит в себе узлы (предыдущий, следующий) список типов Point, которые описывают конкретный узел. Point можно рассматривать как некий атрибут, который может принимать следующие типы

Position — координата
Descriptiom — текстовое описание
Radius — радиус
Lanes — количество полос

каждый нод Street может хранить в себе произвольное количество Point

ну суть здесь не в этом. а в том, что получаю ошибку компиляции функции distance

Error FS0039 The field, constructor or member 'x/y' is not defined.


смысл ошибки понятен, но не совсем понятно, как сказать компилятору, что тип Point на самом деле является Position. пробовал разные способы

pt1: Point(x, y)
pt1: Point(x:float, y: float)
pt1: Position
pt1: Position(x, y)

и так далее

может кто подсказать, как заставить компилятор понять, какой тип я передаю в distance?

благодарю
проклятый антисутенерский закон
Отредактировано 22.07.2019 21:30 zverjuga . Предыдущая версия .
Re: F#, вычисление дистанции между узлами дерева
От: Буравчик Россия  
Дата: 23.07.19 05:27
Оценка: 6 (1)
Здравствуйте, zverjuga, Вы писали:

Z>приветствую. засел за изучение F#. язык и подход для меня новый, все переворачивается с ног на голову, потому прошу помощи. имеется следующий код


Z>
Z>    let distance (pt1: Point) (pt2: Point) =
Z>        let square x = x * x
Z>        sqrt <| square (pt1.x - pt2.x) + square (pt1.y - pt2.y)
Z>


Вот так, наверное:
    let distance_position (pt1: Point) (pt2: Point) =
        match pt1, pt2 with
        | Position (p1x, p1y), Position (p2x, p2y) -> sqrt <| square (p1x - p2x) + square (p1y - p2y)
        | _ -> 0.0
Best regards, Буравчик
Re: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 05:46
Оценка: 6 (1)
Здравствуйте, zverjuga, Вы писали:
Z>
Z>    type Point =
Z>        | Position of x:float * y:float

У вас позиция имеет тип - кортеж двух чисел.
Вы их пытаетесь получить как поля, так не получится. Т.к. полей нет.
Просто переводим сообщение  компилятора на русский !:)

Итак для работы с кортежи используем либо match x with 
либо (fst pos) (snd pos) - первый или второй элемент кортежа.
ну еще есть активные шаблоны. тоже могут помочь в извлечении.
Обычно используют функции помощники для извлечения значений:
[ocaml]
type Position = Position of x:float * y:float
let XPost p = fst p
let YPost p = snd p

Но лучше не тратить время на F#.
Я учил больше года, потом понял, что махать придется в разы больше чем в C#.
Ну если только из академического интереса или в качестве скриптового языка.
Re: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 05:52
Оценка: 6 (1)
Здравствуйте, zverjuga, Вы писали:

Z>приветствую. засел за изучение F#. язык и подход для меня новый, все переворачивается с ног на голову, потому прошу помощи. имеется следующий код


    let getPos p =
        match p with
        | Position (x,y) ->  (x,y)
        | _ -> (0. , 0.)

    let distance (pt1: Point) (pt2: Point) =
        let square x = x * x
        sqrt <| square ((fst (getPos pt1)) - (fst (getPos pt2))) + square ((snd (getPos pt1)) - (snd (getPos pt2)))

Примерно так...
Re: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 06:00
Оценка:
Здравствуйте, zverjuga, Вы писали:

Z>приветствую. засел за изучение F#. язык и подход для меня новый, все переворачивается с ног на голову, потому прошу помощи. имеется следующий код


Z>
Z>module Street
Z>    type Point =
Z>        | Position of x:float * y:float
Z>        | Description of string
Z>        | Radius of float
Z>        | Lanes of uint32
Z>

Вообще, мне кажется вы не правильно используете описание типа,
Это так называемый алгебраический тип данных или по английски DU (дискримэйшн юнион),
т.е. объединение нескольких тип в один общий (родительский и абстрактный) — в вашем случае это Point.
Description, Radius и Lanes(может Lines?) не являеются подтипами Point(точка).
Лучше переписать так:
type Point =
        | Position of x:float * y:float * Description : string *  Radius : float *  Lanes : uint32

Примечание: чаще всего указание типа излишне, ставьте тип только если не комплитица модуль.
или так:
type Position = {  x:float ; y:float ; Description : string ;  Radius : float ;  Lanes : uint32}
type Point = Position

Здесь уже Position нормальный тип вида запись(record) — можете обращаться к полям Point через точку.
Re[2]: F#, вычисление дистанции между узлами дерева
От: takTak  
Дата: 23.07.19 06:12
Оценка:
AA>Но лучше не тратить время на F#.
AA>Я учил больше года, потом понял, что махать придется в разы больше чем в C#.

а в чём конкретно заключается это "больше" ? синтаксис языка выглядит довольно компактно
Re: F#, вычисление дистанции между узлами дерева
От: MadHuman Россия  
Дата: 23.07.19 07:10
Оценка:
Здравствуйте, zverjuga, Вы писали:


Z>смысл ошибки понятен, но не совсем понятно, как сказать компилятору, что тип Point на самом деле является Position. пробовал разные способы


Z>pt1: Point(x, y)

Z>pt1: Point(x:float, y: float)
Z>pt1: Position
Z>pt1: Position(x, y)

Z>и так далее


Z>может кто подсказать, как заставить компилятор понять, какой тип я передаю в distance?


нет способа указать компилятору на уровне декларации типа, что ожидается и допустим только конкретный подтип из DU.
остаётся вариант, только как выше коллеги уже привели, делать явный match.
Re[3]: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 07:35
Оценка:
Здравствуйте, takTak, Вы писали:

AA>>Но лучше не тратить время на F#.

AA>>Я учил больше года, потом понял, что махать придется в разы больше чем в C#.

T>а в чём конкретно заключается это "больше" ? синтаксис языка выглядит довольно компактно


Взять к примеру Dapper. Он заточен под C# и анонимные типы.
В F# придется описать нужные типы, еще учесть nullable поля.
Пробовал пользоваться Type Providers — надо быть гуру F# чтобы это чудо запустилось, последняя попытка Excel — в дизайнере работает,
компилю — не работает(не находит dll). Версия 4.5! Ого, все врукопашную. Причем, поставщиков типа поддерживается главный архитектор языка.
Ну, да ладно. Рекламная пауза. При гораздо меньших ресурсах Nemerle работает гораздо предсказуемее, представляя баланс между ФП и ООП.


синтаксис F# шикарен, тут я согласен, Nemerle конечно не хватает изящества, но он по-крайней мере описывает тип после имени, что уже ставить его наголову выше C#.
Сравните:
    let headers (lines : seq<string>) =
        let printLine s = s |> fprintf out "%s\r\n"
        lines |> Seq.iter printLine
        printLine ""
        out.Flush()


и

        def headers (lines) {
            lines.Iter(ou.WriteLine);
            ou.WriteLine("");
            ou.Flush();
        }


Объективно, что лучше?
Re[2]: F#, вычисление дистанции между узлами дерева
От: zverjuga Беларусь  
Дата: 23.07.19 09:59
Оценка: +1
Здравствуйте, varenikAA, Вы писали:

AA>Но лучше не тратить время на F#.

AA>Я учил больше года, потом понял, что махать придется в разы больше чем в C#

спасибо за совет. но пока что мне он нравится, хочу попробовать его использовать в реальном проекте, чтобы оценить.
проклятый антисутенерский закон
Re[2]: F#, вычисление дистанции между узлами дерева
От: zverjuga Беларусь  
Дата: 23.07.19 10:04
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Вообще, мне кажется вы не правильно используете описание типа,

AA>Лучше переписать так:

да, я думал об этом. но почему я выбрал именно такой подход? прежде всего из предположения, что тип Point будет расширяться, я туда буду добавлять новые сущности по мере разработки. по сути — это атрибуты нода и каждый нод содержит список таких атрибутов. сегодня атрибуты одни, завтра могут быть другими, поэтому и я выбрать такое объединение. если делать как в вашем варианте, то конструкция получится слишком громоздкой по мере увеличения данных/удаления/изменения таких атрибутов.
проклятый антисутенерский закон
Re[3]: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 12:48
Оценка:
Здравствуйте, zverjuga, Вы писали:

Z>Здравствуйте, varenikAA, Вы писали:


AA>>Вообще, мне кажется вы не правильно используете описание типа,

AA>>Лучше переписать так:

Z>да, я думал об этом. но почему я выбрал именно такой подход? прежде всего из предположения, что тип Point будет расширяться, я туда буду добавлять новые сущности по мере разработки. по сути — это атрибуты нода и каждый нод содержит список таких атрибутов. сегодня атрибуты одни, завтра могут быть другими, поэтому и я выбрать такое объединение. если делать как в вашем варианте, то конструкция получится слишком громоздкой по мере увеличения данных/удаления/изменения таких атрибутов.


Тут дело не в громоздкости, а в том что вы неверно понимаете что есть DU, ведь координаты у вас связаны с описанием?
А описание без координат вообще лишено смысла?
То что дискриминаторы идут друг под другом не значит, что они наследуют вышестоящих, они наследуют только базовый Point.
Надеюсь вы это понимаете, все дискриминаторы типа по сути это разные сущности или структуры данных.
DU удобно описывать различные состояния объекта.
До F# на чем писали?
Re[4]: F#, вычисление дистанции между узлами дерева
От: zverjuga Беларусь  
Дата: 23.07.19 13:36
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>А описание без координат вообще лишено смысла?


нет, почему же? если абстрагироваться, то это можно рассматривать как атрибут, который может быть применен к любым другим сущностям.

AA>То что дискриминаторы идут друг под другом не значит, что они наследуют вышестоящих, они наследуют только базовый Point.


я это прекрасно понимаю. дискриминанты можно в какой то мере сравнить с объединениями из С++.

AA>До F# на чем писали?


Swift/C#, и до сих пор пишу.
проклятый антисутенерский закон
Re[5]: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 23.07.19 14:42
Оценка:
Здравствуйте, zverjuga, Вы писали:

Z>Здравствуйте, varenikAA, Вы писали:


AA>>А описание без координат вообще лишено смысла?


Z>нет, почему же? если абстрагироваться, то это можно рассматривать как атрибут, который может быть применен к любым другим сущностям.


AA>>То что дискриминаторы идут друг под другом не значит, что они наследуют вышестоящих, они наследуют только базовый Point.


Z>я это прекрасно понимаю. дискриминанты можно в какой то мере сравнить с объединениями из С++.


AA>>До F# на чем писали?


Z>Swift/C#, и до сих пор пишу.


Собственно, ФП позволяет усложнить (сложность сверх сложности самой задачи) код не хуже ООП.
Пишите о прогрессе в реальном проекте. А то, я пока не вижу особого смысла в F# окромя скриптинга,
хотя и в скриптинге полно хороших альтернатив — начиная от нативных lua, DLang, кончая всякими python, ruby, groovy.

Сила F#, что можно не покидая среды (.Net) C#-разработчику изучать новые приемы.
Настоящая сила F#, кроме красивого синтаксиса:
1. необходимость иметь объявление типа перед использованием, т.е. реализация строго последовательна — автоматически избавляет от проблемы циклических ссылок,
что является признаком плохого дизайна.
2. хвостовая рекурсия и куча функций вместо классов. Сахар, но очень приятный. Когда узнал, что в C# до сих пор нет хвостовой был в шоке.
3. Некоторые вещи красивые из коробки, на вскидку могу вспомнить async и MailboxProcessor — реализация неблокирующего асинхронного доступа к общему ресурсу.
4. слабоватая но все же возможность работать в REPL-режиме. Иногда доставляет удовольствие.

Есть и минусы:
1. нет частичного применения, хоть и пишут что есть, по мне это просто каррирование, т.к. каррировать можно только строго слева направо,
в отличие от Nemerle где частное реализовано полностью, т.е. можно def f1 (a, b, c) {} использовать как def f = f1 (_ , 10, _)
и это будет работать, проверьте в F# такое возможно?
2. Пробовал перевести код из книги Дона Сайма на Nemerle — в местах где были указаны типв в F# в Nemerle указывать не пришлось. Кол-во примерно одинаковое.
3. Жестко зашита реализация, например, в записях — в Nemerle это опция.
4. Нельзя квотирование скомпилить в IL средствами стандартной библиотеки.
5. слишком много операторов утомляют, например:
1 |> (+) <| 2

— каков порядок вычислений?
тоже, что —
(+) 1 2

тоже, что —
1 + 2


Можно долго об этом рассуждать конечно, держите в курсе реализации своего проекта.
Отредактировано 24.07.2019 9:39 vaa . Предыдущая версия .
Re[6]: F#, вычисление дистанции между узлами дерева
От: zverjuga Беларусь  
Дата: 23.07.19 15:22
Оценка: +1
Здравствуйте, varenikAA, Вы писали:

AA>Можно долго об этом рассуждать конечно, держите в курсе реализации своего проекта.


благодарю за советы.
мне показалось, что F# хорошо заточен для удобной обработки массивов, списков, строк и прочее. проект предполагает это, то есть есть огромное дерево, представляющее из себя пересечение улиц, с правилами пересечения перекрестков. и трафик, которые по этому дереву перемещается. трафик — это большой поток машин, которые движутся каждый по своему маршруту, назависимо друг от друга. и над всем этим висит система, которая старается этот трафик оптимизировать и минимизировать, путем переключения сигналов светофором на перекрестках. изучая F# я пришел почему то к выводу, что этот язык намного лучше должен справиться с такой задачей, чем тот же C#.
проклятый антисутенерский закон
Re[4]: F#, вычисление дистанции между узлами дерева
От: takTak  
Дата: 23.07.19 16:50
Оценка:
AA>Пробовал пользоваться Type Providers — надо быть гуру F# чтобы это чудо запустилось, последняя попытка Excel — в дизайнере работает,

AA>Объективно, что лучше?


жалко, я как раз думал, что type providers — работающая фишка одного только f#

трудно сказать: ты пытаешься сравнить "хелло вёлд" с "хелло вёлдом", но вроде как f#- это инструмент скорее для выражения state machines и сложных workflow без единого let, к вводу-выводу это как бы боком
Re[6]: F#, вычисление дистанции между узлами дерева
От: Poopy Joe Бельгия  
Дата: 18.08.19 17:13
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Собственно, ФП позволяет усложнить (сложность сверх сложности самой задачи) код не хуже ООП.

На любом языке, при должном старании, можно писать говнокод.

AA>Настоящая сила F#, кроме красивого синтаксиса:

В том, что он функциональный, в отличии от C#.

AA>1. нет частичного применения, хоть и пишут что есть, по мне это просто каррирование, т.к. каррировать можно только строго слева направо,

AA>в отличие от Nemerle где частное реализовано полностью, т.е. можно def f1 (a, b, c) {} использовать как def f = f1 (_ , 10, _)
AA>и это будет работать, проверьте в F# такое возможно?
И что тут получится? Какой будет возвращаемый тип?
Re[7]: F#, вычисление дистанции между узлами дерева
От: Mumitroller Беларусь  
Дата: 19.08.19 06:15
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

AA>>1. нет частичного применения, хоть и пишут что есть, по мне это просто каррирование, т.к. каррировать можно только строго слева направо,

AA>>в отличие от Nemerle где частное реализовано полностью, т.е. можно def f1 (a, b, c) {} использовать как def f = f1 (_ , 10, _)
AA>>и это будет работать, проверьте в F# такое возможно?
PJ>И что тут получится? Какой будет возвращаемый тип?

Вроде бы достаточно очевидно — получится функция f с двумя аргументами, которая возвращает значение такого же типа, как и f1.

Mumitroller
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[8]: F#, вычисление дистанции между узлами дерева
От: Poopy Joe Бельгия  
Дата: 19.08.19 06:53
Оценка:
Здравствуйте, Mumitroller, Вы писали:

M>Вроде бы достаточно очевидно — получится функция f с двумя аргументами, которая возвращает значение такого же типа, как и f1.


Что там очевидного? Ни имени аргументов, ни их порядка. В случае f# это может выглядеть как
let f a b c = fun a c -> ... или let f a b с = fun c a -> ...
Отредактировано 19.08.2019 7:03 Poopy Joe . Предыдущая версия . Еще …
Отредактировано 19.08.2019 6:54 Poopy Joe . Предыдущая версия .
Re[9]: F#, вычисление дистанции между узлами дерева
От: varenikAA https://www.youtube.com/playlist?list=PLtrvASfI1KW7VOYRKjglcagQzWLoxlncl
Дата: 19.08.19 08:17
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Здравствуйте, Mumitroller, Вы писали:


M>>Вроде бы достаточно очевидно — получится функция f с двумя аргументами, которая возвращает значение такого же типа, как и f1.


PJ>Что там очевидного? Ни имени аргументов, ни их порядка. В случае f# это может выглядеть как

PJ>let f a b c = fun a c -> ... или let f a b с = fun c a -> ...

В моем случае функция от 3 аргументов преобразуется в функцию от 2-х. Непонятно, что вы имели ввиду,
функцию от 2-х аргументов превратили в функцию от 3-х? Честно, поясните свой код. Или приведите более понятный пример с контекстом.
То, что в F# называют partial application, я представляю примерно так:
let f a b = a + b
let pa b = f 10
// pa 5;; => 15


или я ошибаюсь?
Отредактировано 19.08.2019 8:20 vaa . Предыдущая версия . Еще …
Отредактировано 19.08.2019 8:19 vaa . Предыдущая версия .
Re[10]: F#, вычисление дистанции между узлами дерева
От: Poopy Joe Бельгия  
Дата: 19.08.19 09:37
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>В моем случае функция от 3 аргументов преобразуется в функцию от 2-х.

Я тоже самое и сделал. let f a b c = fun a c — (a, c) эквивалентно let f _ b _ = fun a c -> (a, c)
Но я не понял происходит c аргументами в немерле, с плейсхолдерами, которые, очевидно, имеют другое значение.
Хотя, наверно, имелось ввиду такая форма let f a c = f1 (a, 10, c), но тут я не вижу вообще ничего особенного, это в любом языке делается.

AA>То, что в F# называют partial application, я представляю примерно так:

В f# partial application называют то же, что и везде — функция от N аргументов использует часть из них и возвращает функцию которая использует остаток. Формально это происходит всегда, на уровне семантики, потому что функции в f#, как и в хаскеле, имеют один аргумент. Т.е. функция f a b c семантически имеет тип a -> b -> c -> d, это называет каррирование.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.