приветствую. засел за изучение 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. пробовал разные способы
Здравствуйте, 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
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#.
Ну если только из академического интереса или в качестве скриптового языка.
Здравствуйте, 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)))
Здравствуйте, 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#, вычисление дистанции между узлами дерева
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#, вычисление дистанции между узлами дерева
Здравствуйте, 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()
Здравствуйте, varenikAA, Вы писали:
AA>Вообще, мне кажется вы не правильно используете описание типа, AA>Лучше переписать так:
да, я думал об этом. но почему я выбрал именно такой подход? прежде всего из предположения, что тип Point будет расширяться, я туда буду добавлять новые сущности по мере разработки. по сути — это атрибуты нода и каждый нод содержит список таких атрибутов. сегодня атрибуты одни, завтра могут быть другими, поэтому и я выбрать такое объединение. если делать как в вашем варианте, то конструкция получится слишком громоздкой по мере увеличения данных/удаления/изменения таких атрибутов.
проклятый антисутенерский закон
Re[3]: F#, вычисление дистанции между узлами дерева
Здравствуйте, zverjuga, Вы писали:
Z>Здравствуйте, varenikAA, Вы писали:
AA>>Вообще, мне кажется вы не правильно используете описание типа, AA>>Лучше переписать так:
Z>да, я думал об этом. но почему я выбрал именно такой подход? прежде всего из предположения, что тип Point будет расширяться, я туда буду добавлять новые сущности по мере разработки. по сути — это атрибуты нода и каждый нод содержит список таких атрибутов. сегодня атрибуты одни, завтра могут быть другими, поэтому и я выбрать такое объединение. если делать как в вашем варианте, то конструкция получится слишком громоздкой по мере увеличения данных/удаления/изменения таких атрибутов.
Тут дело не в громоздкости, а в том что вы неверно понимаете что есть DU, ведь координаты у вас связаны с описанием?
А описание без координат вообще лишено смысла?
То что дискриминаторы идут друг под другом не значит, что они наследуют вышестоящих, они наследуют только базовый Point.
Надеюсь вы это понимаете, все дискриминаторы типа по сути это разные сущности или структуры данных.
DU удобно описывать различные состояния объекта.
До F# на чем писали?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: F#, вычисление дистанции между узлами дерева
Здравствуйте, varenikAA, Вы писали:
AA>А описание без координат вообще лишено смысла?
нет, почему же? если абстрагироваться, то это можно рассматривать как атрибут, который может быть применен к любым другим сущностям.
AA>То что дискриминаторы идут друг под другом не значит, что они наследуют вышестоящих, они наследуют только базовый Point.
я это прекрасно понимаю. дискриминанты можно в какой то мере сравнить с объединениями из С++.
AA>До F# на чем писали?
Swift/C#, и до сих пор пишу.
проклятый антисутенерский закон
Re[5]: F#, вычисление дистанции между узлами дерева
Здравствуйте, 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
Можно долго об этом рассуждать конечно, держите в курсе реализации своего проекта.
Здравствуйте, varenikAA, Вы писали:
AA>Можно долго об этом рассуждать конечно, держите в курсе реализации своего проекта.
благодарю за советы.
мне показалось, что F# хорошо заточен для удобной обработки массивов, списков, строк и прочее. проект предполагает это, то есть есть огромное дерево, представляющее из себя пересечение улиц, с правилами пересечения перекрестков. и трафик, которые по этому дереву перемещается. трафик — это большой поток машин, которые движутся каждый по своему маршруту, назависимо друг от друга. и над всем этим висит система, которая старается этот трафик оптимизировать и минимизировать, путем переключения сигналов светофором на перекрестках. изучая F# я пришел почему то к выводу, что этот язык намного лучше должен справиться с такой задачей, чем тот же C#.
проклятый антисутенерский закон
Re[4]: F#, вычисление дистанции между узлами дерева
AA>Пробовал пользоваться Type Providers — надо быть гуру F# чтобы это чудо запустилось, последняя попытка Excel — в дизайнере работает,
AA>Объективно, что лучше?
жалко, я как раз думал, что type providers — работающая фишка одного только f#
трудно сказать: ты пытаешься сравнить "хелло вёлд" с "хелло вёлдом", но вроде как f#- это инструмент скорее для выражения state machines и сложных workflow без единого let, к вводу-выводу это как бы боком
Re[6]: F#, вычисление дистанции между узлами дерева
Здравствуйте, varenikAA, Вы писали:
AA>Собственно, ФП позволяет усложнить (сложность сверх сложности самой задачи) код не хуже ООП.
На любом языке, при должном старании, можно писать говнокод.
AA>Настоящая сила F#, кроме красивого синтаксиса:
В том, что он функциональный, в отличии от C#.
AA>1. нет частичного применения, хоть и пишут что есть, по мне это просто каррирование, т.к. каррировать можно только строго слева направо, AA>в отличие от Nemerle где частное реализовано полностью, т.е. можно def f1 (a, b, c) {} использовать как def f = f1 (_ , 10, _) AA>и это будет работать, проверьте в F# такое возможно?
И что тут получится? Какой будет возвращаемый тип?
Re[7]: F#, вычисление дистанции между узлами дерева
Здравствуйте, 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#, вычисление дистанции между узлами дерева
Здравствуйте, Mumitroller, Вы писали:
M>Вроде бы достаточно очевидно — получится функция f с двумя аргументами, которая возвращает значение такого же типа, как и f1.
Что там очевидного? Ни имени аргументов, ни их порядка. В случае f# это может выглядеть как
let f a b c = fun a c -> ... или let f a b с = fun c a -> ...
Здравствуйте, 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, я представляю примерно так:
Здравствуйте, 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, это называет каррирование.
Re[9]: F#, вычисление дистанции между узлами дерева
Здравствуйте, 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 -> ...
Просто скажу, что без лишних ухищрений в F# возможен только первый вариант:
using System.Console;
def f1 (a, b, c) {
a * b / c
};
def partialFunction1 = f1 (10 , _ , _);
def partialFunction2 = f1 (_ , 10, _);
def partialFunction3 = f1 (_ , _ , 10);
def regularFunction (a, c) {
f1 (a, 10, c)
};
В этом случае:
let f a b c = fun a c -> a + b + c
вероятно лямбда перекроет аргументы a и c и сможет использовать значение b.
Только зачем? ведь применение f к 3 аргументам создаст функцию с двумя аргументами (int -> int -> int).
Непонятно, однако.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[10]: F#, вычисление дистанции между узлами дерева
AA>def partialFunction1 = f1 (10 , _ , _); AA>def partialFunction2 = f1 (_ , 10, _); AA>def partialFunction3 = f1 (_ , _ , 10);
AA>def regularFunction (a, c) { AA> f1 (a, 10, c) AA>};
Эээ... А в чем собственно разница между всеми этими вариантами? А наличии неявных аргументов? И что это дает в сравнении с явными?
AA>Только зачем? ведь применение f к 3 аргументам создаст функцию с двумя аргументами (int -> int -> int).
Понятия не имею, пример же сферический. Нет этих аргументов в момент использования, а есть только b, например.
Re[4]: F#, вычисление дистанции между узлами дерева
Здравствуйте, varenikAA, Вы писали:
AA>синтаксис F# шикарен, тут я согласен, Nemerle конечно не хватает изящества, но он по-крайней мере описывает тип после имени, что уже ставить его наголову выше C#. AA>Сравните: AA>
AA> let headers (lines : seq<string>) =
AA> let printLine s = s |> fprintf out "%s\r\n"
AA> lines |> Seq.iter printLine
AA> printLine ""
AA> out.Flush()
AA>