2015-02-01 5 views
2

Я хочу определить функцию, которая принимает необязательный аргумент, который является функцией ('a ->' b). Значение по умолчанию должно быть тождеством, которое на самом деле ('a -> 'a), но я не вижу причин, почему он не должен быть совместим с более общим ('a -> 'b). Когда я пытаюсь:как заставить OCaml вывести более общий тип?

let optional_apply ?f i = 
    match f with 
    | None -> i + 4 
    | Some fn -> fn (i + 4) 

Я всегда получаю узкий тип ?f:(int -> int) -> int -> int. Но я хочу сохранить f как int -> 'b. Что я могу сделать? Или это просто неудобно, так как optional_apply не будет иметь определенный тип? Если да, то как мне получить аналогичную функциональность?

ответ

3

Невозможно, аргумент f не может быть дополнительным. Простое объяснение заключается в том, что необязательные параметры - это просто синтаксический сахар. Так без сахара ваша функция может быть переписано в следующем виде:

let optional_apply f n = match f with 
    | Some f -> f (n + 4) 
    | None -> (n + 4) 

И здесь позволяет нам проверки типов только один тип для f: int -> int. Если это допустило тип int -> 'a, то путь выражения None был бы несостоятельным. Другими словами, в зависимости от того, f - None или Some, optional_apply будет оценивать разные типы. И это считается необоснованным.

Лучший способ доказать необоснованность, чтобы дать простой пример, когда программу проверка позволит необоснованной программу:

let f = ref None 
let g n = optional_apply ?f:!f n 

с этими определениями, если типа проверки позволил f параметру оставаться полиморфным, то мы можем в любом time "break" g function by change f ссылка на что-нибудь еще.

+0

Итак, способ думать о необязательных аргументах - это типы 'option', которые фиксируются во время определения функции. Я ошибочно представлял себе что-то вроде ленивой типизирующей конструкции, с которой не нужно смотреть, пока это не понадобится. Но это, вероятно, вздор в контексте Окамла. – user3240588

+0

Ваш второй пример - просвещающий, спасибо! – user3240588

2

Это не подходит к общему типу ('a -> 'b). Вот почему:

  • Первый шаблон, None -> i + 4 имеет тип int, тем самым ограничивая функцию возвращаемого типа для int.

  • Второй узор, Some fn -> fn (i + 4) должен тогда также быть типа int. Поскольку (i + 4) имеет тип int, fn должен взять и вернуть int, таким образом int -> int.


Лучший вариант я могу думать о maybe функции в Haskell, типа ('a -> 'b) -> 'b -> 'a option -> 'b:

let maybe fn backup opt = match opt with 
    | Some v -> fn v 
    | None -> backup 
;; 

... которые вы, вероятно, может адаптироваться к прецеденту.

+0

Я согласен с вашими объяснениями. Просто трудно понять, почему так должно быть. С необязательным аргументом 'f' вместо'? F', функция представляет собой просто «приложение», и нет проблемы с сохранением типа 'f' general. 'apply' является полиморфным и может быть повторно использован с' f' разных типов, без проблем. – user3240588

Смежные вопросы