Вывод типа F# с помощью Array.sum

Почему я должен сообщать F#, использую ли я int или float в этой строке? let total counts = Array.sum counts к let total (counts:int[]) = Array.sum counts ?

Исходя из sml, я нахожу вывод типа F# слишком ограничительным.

P.S. Я мало что знаю о ландшафте функциональных языков, но было бы интересно, если бы кто-нибудь просветил меня, какие F-языки используются в дикой природе.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
97
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Согласно сообщению об ошибке, я понимаю, что проблема в том, что вы должны ограничить его типом, поддерживающим оператор «+».

Я предполагаю, что это делают и float, и int, но не тип по умолчанию «obj», который вы получаете, если не указываете тип массива.

В F# компиляция является однопроходной и (в основном) строго прямой. Я считаю, что это сделано для улучшения времени компиляции, но я не уверен. В результате в выражении Array.sum counts функция sum не знает, какой тип counts, если вы не добавите аннотацию типа.

Вы можете написать вычислительно эквивалентное выражение counts |> Array.sum и, поскольку counts появляется раньше в файле, sum может правильно разрешить тип. Это одна из причин, по которой оператор трубопровода|> так часто встречается в коде F#.

(Ключевые слова rec и and позволяют компилятору ссылаться на вещи вперед в исходном файле, чтобы разрешить взаимно рекурсивные функции и типы, а member в определениях классов взаимно рекурсивны по умолчанию, но это исключение.)

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

TheQuickBrownFox 23.03.2022 13:38
Ответ принят как подходящий

Не прямой ответ, но у вас есть возможность создать встроенную функцию, которая будет более общей:

let inline total counts = Array.sum counts

Тип this автоматически выводится с необходимыми статически разрешенными параметрами типа:

> val inline total:
  counts:  ^a[] ->  ^a
    when  ^a: (static member (+) :  ^a *  ^a ->  ^a) and
          ^a: (static member get_Zero: ->  ^a)

Использование:

total [|1; 2; 3|] // 6
total [|1.; 2.; 3.|] // 6.0

Привет, спасибо, это гораздо менее ограничительно. После просмотра документов кажется, что встроенные файлы следует использовать с осторожностью. «Встроенные функции — это функции, интегрированные непосредственно в вызывающий код». Это может привести к «утечке» кода между модулями без повторного использования скомпилированного кода библиотеки. Является ли хорошей практикой использование встроенных функций только внутри?

Alex_ 23.03.2022 21:35

@Alex_ inline в F# означает не то, что означает в большинстве других контекстов. Это неправильное название, правда. Каков источник вашей цитаты?

phoog 24.03.2022 09:54

@Alex_ Определенно этим можно злоупотреблять и сделать код чрезмерно сложным, а компиляцию очень медленной. Но для некоторых очень общих библиотечных функций это может быть полезно. По этой причине несколько функций основной библиотеки F# помечены как встроенные.

TheQuickBrownFox 24.03.2022 13:16

Документы @phoog MSDN. docs.microsoft.com/en-us/dotnet/fsharp/language-reference/…

Alex_ 28.03.2022 06:06

Также см. мой дополнительный вопрос. stackoverflow.com/questions/71642273/…

Alex_ 28.03.2022 06:07

@Alex_ спасибо. Я подозреваю, что это определение немного вводит в заблуждение в контексте F#, несмотря на его появление в документации по F#. Встраивание традиционно означает буквально интеграцию кода функции в вызывающую функцию, и я вполне уверен, что компилятор F# этого не делает: в F# функция inline может быть сколь угодно длинной, а ключевое слово имеет отношение к программисту из-за вывода типа, а не спектакль. Попробуйте декомпилировать программу F#, в которой используются встроенные функции, и вы увидите, что это обычные вызовы IL.

phoog 28.03.2022 13:14

@phoog Я считаю, что ключевое слово inline действительно может встроить функцию, как вы описываете, но только при определенных условиях (мне неизвестных). Это определенно может повлиять на производительность. Например. прямой оператор |> — это просто встроенная функция.

TheQuickBrownFox 28.03.2022 13:43

@phoog Это можно увидеть здесь. Функция total не вызывается при компиляции/декомпиляции в C#. Даже Array.sum не вызывается, потому что он также встроен.

TheQuickBrownFox 28.03.2022 13:52

Но вопрос о том, встроена ли функция в традиционном смысле, зависит от JIT-компилятора. Оператор прямого канала, определяемый как inline, аналогично для вывода типа; в библиотеках F# .NET нет функции переадресации конвейера (так же, как нет функции (+) — это что-то вроде фикции, поддерживаемой компилятором F#). Компилятор F# мая встраивает функцию, помеченную inline, как в вашем примере, но в некоторых случаях это делает не можешь (особенно let rec inline ...). Если вы скопируете реализацию Array.sum в свой собственный модуль и будете использовать ее, встраивает ли это компилятор?

phoog 28.03.2022 14:03

Кроме того, компилятор F# сильно изменился с тех пор, как я в последний раз подробно исследовал его. Я подозреваю, что тот, на кого я смотрел много лет назад, вероятно, просто позвонил бы Array.sum, но я не мог поклясться в этом. Конечно, если функция inline состоит из 100 строк, ее не следует встраивать, особенно если она вызывается более одного раза. Интересно, есть ли способ предотвратить явное встраивание функций inline; то есть ограничить его действие выводом типа. Это было бы полезно для предотвращения утечки, о которой вы беспокоитесь. (Это исправленная версия предыдущего комментария.)

phoog 28.03.2022 15:00

Другие вопросы по теме