Должны ли явные аргументы типа функции включать все универсальные типы в подписи?

#generics #f#

#универсальные #f#

Вопрос:

Следующий код имеет подпись 'c -> 'c :

 let f (x: 'c) = x
  

Однако следующий код имеет подпись obj -> obj :

 let f<'a> (x: 'c) = x
  

Добавление 'c параметра type исправляет сигнатуру, возвращая ее к 'c -> 'c :

 let f<'a, 'c> (x: 'c) = x
  

Возможно ли явно объявить только некоторые из подписей? Я в основном хочу что-то вроде

 let f<'a> (x: MyType<'c>) =
  let foo = doSomethingBasedOn typeof<'a>
  processXWithoutCaringAboutTypeC x foo
  

Это что-то вроде десериализации или распаковки, поэтому мне нужны явные аргументы типа для 'a , но меня действительно не волнует тип 'c и я предпочел бы не указывать его явно (или подстановочный тип).

Комментарии:

1. Я предполагаю, что проблема в том, что в вашем последнем примере processXWithoutCaringAboutTypeC нужно будет знать о типе 'c , ожидая его в качестве аргумента типа (который обычно выводится компилятором). Я сомневаюсь, что вы можете сделать что-то лучше, чем let f<'a> (x : MyType<_>) = ...

2. Вы уверены, что это не ограничивает ‘c значением obj? (Не перед компьютером прямо сейчас)

3. Что вы подразумеваете под «этим»?

4. let f<'a> (x : MyType<_>) = ... . Только что протестированный сейчас, он действительно ограничивает x до MyType<obj> .

5. В таком случае, я подозреваю, что ваша функция processXWithoutCaringAboutTypeC вообще не принимает параметр типа. Можете ли вы показать его подпись?

Ответ №1:

Чтобы прямо ответить на ваш вопрос, нет способа включить только подмножество общих параметров в явный список общих параметров ( <'a,'b,...> ), ни при определении, ни при использовании функции. Но из вашего описания не ясно, что это действительно важно для вашего варианта использования.

  1. То, что вы явно используете аргументы универсального типа в определении функции, не означает, что вам также нужно делать это при вызове функции:

     let f<'a,'c> (x: 'c) = x
    f 1  # works fine with type inference
      
  2. Если возвращаемый тип f includes 'a каким-либо образом в вашем втором случае, то вывод типа, вероятно, также позволит вам пропустить явные параметры типа даже в определении f .

Однако, если 'a нигде не отображается в сигнатуре f (как часть ввода или вывода) и это существенным образом влияет на поведение, тогда его нужно будет указать явно как аргумент типа при вызове f , потому что вывод типа F # не может определить, каким он должен быть, что заставит вас указать и другие аргументы типа (хотя, возможно, в качестве подстановочных знаков).

Комментарии:

1. Спасибо. К сожалению для меня, случай действительно является вашим пунктом № 2. MyType<_> содержит элементы типа System.Type и 'a используется для сравнения с этим типом. Параметр type to MyType<_> не имеет отношения к данному конкретному сравнению. Поэтому я должен указать 'a явно при вызове.

2. В этом случае вместо использования универсального параметра 'a вы можете просто получить параметр ta типа System.Type и выполнить сравнение, которое вам нужно с ним выполнить. Если вы передаете ta в качестве первого параметра, то вы можете даже использовать частичное применение.

3. Да, фактически, я только начал экспериментировать с этим. 🙂 Спасибо!