В функциональном языке неопределенный (переменный) тип, который вы получаете от функции, в основном должен появляться где-то в типе, который вы передаете. В противном случае, откуда берется значение?Таким образом, нет (полезных) функций типа 'a -> 'b.
. Это может помочь подумать о типах, которые вы ожидаете передать своей функции, и о том, как функция экстрактора будет относиться к ним.Должно быть возможно иметь довольно прямое отношение.Борьба с системой типов обычно означает, что вы пытаетесь сделать что-то, что может неожиданно потерпеть неудачу, что и пытается предотвратить система типов.
Редактировать:
Возможно, я пытаюсь сказать, что 'a
и 'b
, типы ввода и вывода вашей функции экстрактора, не будут произвольными типами.Тип ввода 'a
, вероятно, как-то связан с типом 'c
.Аналогично, тип результата 'b
, вероятно, будет связан с типом возврата функции xxx
в целом.Без дополнительной информации об этих отношениях трудно вносить предложения.
Если вы попытаетесь представить их как независимые, произвольные типы, вы столкнетесь с параметрической невозможностью, о которой я говорил выше.(Это также требует расширенной типизации, полиморфизм ранга 2, я думаю, что это так.)
В качестве простого примера, скажем, что 'a
и 'c
- это один и тот же тип, а 'b
- это возвращаемый типфункция.Тогда ваша функция должна выглядеть примерно так:
let xxx ?extractor s =
match extractor with
| Some f -> f s
| None -> s
Это поведение, которое вы хотели: функция извлечения по умолчанию - это функция идентификации.Но это также приводит к тому, что тип возвращаемого значения f
совпадает с его типом ввода.Таким образом, тип xxx:
val xxx : ?extractor:('a -> 'a) -> 'a -> 'a
Если только вы не хотите стать очень причудливым, на самом деле нет никакого способа обойти это, и я подозреваю, что причудливое решение представило бы сложности, которые перевесили бы удобство наличия дополнительного параметра.
Может быть, будет работать две функции.Чтобы продолжить упрощенный пример, они будут выглядеть следующим образом:
# let xxx extractor s = extractor s;;
val xxx : ('a -> 'b) -> 'a -> 'b = <fun>
# let xxx_id s = xxx (fun x -> x) s;;
val xxx_id : 'a -> 'a = <fun>
Я думаю, что у них есть типы, которые вы хотите, и единственное неудобство в том, что у вас есть два разных имени.