2016-09-13 2 views
3

У меня есть два типа примеров, определенные в следующем порядке:определение типа и вывод типов в F #

type Quote = {QuoteNum: decimal option; ShipToID: decimal option} 
type Sales = {SalesNum: decimal option; ShipToID: decimal option} 

, и я пытаюсь написать функцию, которая может принимать оба типа:

let fx (y: Map<decimal option, _ list>) = 
    y 
    |> Map.map (fun key list -> list 
            |> List.map (fun x -> x.ShipToID)) 

Когда я пытаюсь передать Map<decimal option, Quote list> функции, я получаю сообщение об ошибке:

Type mismatch. Expecting a 
Map<decimal option,Sales list>  
but given a 
    Map<decimal option,Quote list> 

Я бы подумал, что я бы способный передать карту обоих типов функции, но компилятор, кажется, делает вывод, что для функции приемлема только Map<decimal option, Sales list>. Я подозреваю, что компилятор «видит» тип Sales совсем недавно и предполагает, что это то, что нужно функции. Я думал, что я сделал функцию относительно общей, включив _ в аннотацию типа.

Как я могу заставить функцию принять оба типа? Могу ли я это сделать без переопределения самих типов?

+0

Типы, которые вы определили, не являются картами, а типами записей, и они разные. –

ответ

4

Ваши подозрения верны. F # нужно вывести один конкретный тип там, поэтому будет использовать самый последний подходящий тип, который он находит.

Вы можете заставить его работать, указав интерфейс с полем ShipToID и реализуя его оба типа (не уверен, что это считается переопределением типов для вас) или предоставляя функцию-геттер для извлечения значения поля (которое позволяют сохранить функцию родовое):

let fx (shipToIdGetter: 'a -> decimal option) (y: Map<decimal option, 'a list>) = 
    y 
    |> Map.map (fun key list -> 
        list 
        |> List.map (fun x -> shipToIdGetter x)) 

Ваш код будет работать, как написано, если F # поддерживается полиморфизм строк (что случается быть для OCaml).

4

Хотя я считаю, что ответ - это путь, у вас также есть выбор для использования inline и member constraints (или статический утиный набор текста ... если это действительный термин). Ради полноты:

type Quote = {QuoteNum: decimal option; ShipToID: decimal option} 
type Sales = {SalesNum: decimal option; ShipToID: decimal option} 

let inline fx (y: Map<decimal option, 'a list>) = 
    let inline getId x = (^a : (member ShipToID : decimal option) x) 

    y |> Map.map (fun key list -> list |> List.map getId) 


let q : Quote = { QuoteNum = None; ShipToID = None} 
let s : Sales = { SalesNum = None; ShipToID = None} 

fx <| Map.ofList [ None, [q]] 
fx <| Map.ofList [ None, [s]] 

getId функция использует достаточно неопределенна синтаксис для вызова ShipToID элемент, основанный на ^a-х ожидаемой структуры.

+2

FYI - Терминология для этого - «параметры статического разрешения» - см. Https://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/generics/statically-resolved-type-parameters –

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