Общие сведения об ошибках ограничения значений F #

Я не понимаю, как работает ограничение значения в F #. Я также прочитал объяснение в wiki в виде документации MSDN. Я не понимаю:

  1. Почему, например, это дает мне ошибку ограничения значения (взято из этот вопрос):

    let toleq (e:float<_>) a b = (abs ( a - b ) ) < e
    

    Но этого не происходит:

    let toleq e (a:float<_>) b = (abs ( a - b ) ) < e
    
  2. Это обобщенно хорошо ...

    let is_bigger a b = a < b
    

    но это не так (это указано как int):

    let add a b = a + b
    
  3. Почему функции с неявными параметрами генерируют ограничение значения:

    это:

    let item_count = List.fold (fun acc _ -> 1 + acc) 0
    

    против этого:

    let item_count l = List.fold (fun acc _ -> 1 + acc) 0 l
    

    (Имейте в виду, что если я использую эту функцию во фрагменте кода, ошибка VR исчезнет, ​​но тогда функция будет указана для того типа, для которого я ее использовал, и я хочу, чтобы она была обобщена)

Как это работает?

(Я использую последнюю версию F #, v1.9.6.16)


person Dave Berk    schedule 15.07.2009    source источник
comment
Перекрестная ссылка на другой вопрос по той же теме: stackoverflow.com/questions/416508/   -  person Benjol    schedule 20.07.2009
comment
Так же, как обновление этого - case (1), скорее всего, был ошибкой, так как он больше не вызывает ошибки.   -  person Phillip Carter    schedule 15.12.2020


Ответы (3)


РЕДАКТИРОВАТЬ

Более подробная / свежая информация находится здесь: Сохранение частично примененной функции в общем

(оригинал ниже)

Я думаю, что прагматичный момент здесь состоит в том, чтобы не пытаться понять это слишком глубоко, а скорее знать пару общих стратегий, чтобы пройти через виртуальную реальность и продолжить свою работу. Это что-то вроде ответа «отговорки», но я не уверен, что имеет смысл тратить время на понимание внутренних особенностей системы типов F # (которая продолжает незначительно меняться от выпуска к выпуску).

Я бы ратовал за две основные стратегии. Во-первых, если вы определяете значение с помощью типа функции (введите со стрелкой '->'), убедитесь, что это синтаксическая функция, выполнив eta-conversion:

// function that looks like a value, problem
let tupleList = List.map (fun x -> x,x)
// make it a syntactic function by adding argument to both sides
let tupleList l = List.map (fun x -> x,x) l

Во-вторых, если вы все еще сталкиваетесь с проблемами VR / обобщения, укажите всю сигнатуру типа, чтобы сказать, что вы хотите (а затем «отступите», как позволяет F #):

// below has a problem...
let toleq (e:float<_>) a b = (abs ( a - b ) ) < e
// so be fully explicit, get it working...
let toleq<[<Measure>]'u> (e:float<'u>) (a:float<'u>) (b:float<'u>) : bool = 
    (abs ( a - b ) ) < e
// then can experiment with removing annotations one-by-one...
let toleq<[<Measure>]'u> e (a:float<'u>) b = (abs ( a - b ) ) < e

Я думаю, что эти две стратегии - лучший прагматический совет. Тем не менее, вот моя попытка ответить на ваши конкретные вопросы.

  1. Я не знаю.

  2. '>' - это полностью универсальная функция ('a ->' a -> bool), которая работает для всех типов, и поэтому is_bigger обобщает. С другой стороны, «+» - это «встроенная» функция, которая работает с несколькими примитивными типами и определенным классом других типов; он может быть обобщен только внутри других «встроенных» функций, в противном случае он должен быть привязан к определенному типу (или по умолчанию будет использоваться значение «int»). («Встроенный» метод специального полиморфизма - это то, как математические операторы в F # преодолевают недостаток «классов типов».)

  3. Это проблема «синтаксической функции», которую я обсуждал выше; 'давайте скомпилируем в поля / свойства, которые, в отличие от функций, не могут быть общими. Поэтому, если вы хотите, чтобы он был универсальным, сделайте его функцией. (См. Также этот вопрос за еще одно исключение из этого правила.)

person Brian    schedule 15.07.2009
comment
Дмитрий недавно написал об этом хороший пост: blogs.msdn.com/b/mulambda/archive/2010/05/01/ - person Brian; 02.07.2010

Ограничение значений было введено для решения некоторых проблем с полиморфизмом при наличии побочных эффектов. F # наследует это от OCaml, и я считаю, что ограничение значений существует во всех вариантах ML. Вот несколько подробнее ссылки для прочтения, помимо ссылок, которые вы цитировали. Поскольку Haskell чистый, на него не распространяется это ограничение.

Что касается ваших вопросов, я думаю, что вопрос 3 действительно связан с ограничением ценности, а первые два - нет.

person Wei Hu    schedule 17.07.2009
comment
да. OCaml имеет ослабленное ограничение значений, позволяющее использовать переменные необобщенного типа на верхнем уровне в REPL, где они отображаются как '_a, а не как 'a. Последнее означает, что код полиморфен и работает для всех типов 'a, тогда как первый означает, что код является мономорфным для этого типа и работает только для одного конкретного типа '_a, который еще не определен. Это упрощается тем фактом, что OCaml использует единообразное представление данных для всех полиморфных данных. В F # это было бы сложнее, потому что обобщенным дженерикам нужно, чтобы при компиляции был известен точный мономорфный тип. - person J D; 22.02.2017

Никто, включая людей из команды F #, не знает сколько-нибудь значимого ответа на этот вопрос.

Система вывода типов F # в точности похожа на грамматику VB6 в том смысле, что компилятор определяет истину.

Прискорбно, но факт.

person user128807    schedule 15.07.2009
comment
Бьюсь об заклад, Дон знает ответ. И F # все еще находится в стадии бета-тестирования. В какой-то момент нам придется укрепить спецификацию. И компилятор - это не черный ящик; исходный код компилятора F # находится в свободном доступе. Все это говорит о том, что я не отрицал вас, поскольку по большей части я не согласен (вряд ли кто-то «знает», и отсутствие краткой спецификации действительно прискорбно). - person Brian; 16.07.2009
comment
У каждого языка есть свои укромные уголки. F # по большей части очень стабильный, очень элегантный и практичный язык (ИМХО). Очевидно, работа над ним все еще продолжается, но по сравнению с некоторыми другими языками разработки (без именования имен) будущее F # определенно светлое. Тем не менее, я тоже не отрицал вас. - person Dave Berk; 16.07.2009
comment
@Brian Don знает ответ только потому, что у него есть доступ к источнику. В F # нет теории вывода типов. - person user128807; 16.07.2009
comment
@ Дэйв Берк: Я считаю F # красивым языком. Фактически, я управляю группой пользователей F #. Однако из этого не следует, что у него есть красивый механизм вывода типов. - person user128807; 16.07.2009
comment
@Brian это все еще верно сегодня (2014)? что вывод типа F # сложен и определяется только самим источником? Вы бы все равно ответили "Я не знаю" на первый вопрос? - person Goswin; 20.03.2014
comment
Я нахожу все эти утверждения о выводе типов в F # странными. Ограничение значения предназначено для обработки случая, когда переменная необобщенного типа ускользает на верхний уровень. - person J D; 22.02.2017