#f#
Вопрос:
Как мне ввести, скажем, функцию, которая принимает запись, содержащую поле a
и любое другое поле?
Возможен ли какой-либо эквивалент этой стандартной функции ML в F#?
fun f {a: string, ...} = "Hello" ^ a;
Попробовал следующее, но это, похоже, не является синтаксически корректным:
let f (r: {|a: string; _|}) = impl;
let g (r: {|a: string; ...|}) = impl;
Ответ №1:
Вы можете достичь такого рода ограничений с помощью статически разрешенных параметров типа, таких как:
let inline f< ^T when ^T: (member a: string)> (r: ^T) = ()
f {| a = "yeet" |} // compiles
f {| a = "yeet"; b = "yote" |} // compiles
f {| b = "yote" |} // error
Обратите внимание, что это не только для анонимных записей. Это будет справедливо для любого типа, у которого есть член с указанной подписью.
Мне также нравится скрывать эти вещи за модулем и извлекать неприятные вещи SRTP в активный шаблон, например так:
module M =
let inline private (|HasName|) x = (^a : (member Name: string) x)
let inline printName (HasName name) = printfn $"{name}"
type Person1 = { Name: string; Age: int }
type Person2 = { Name: string; Age: int; IsFunny: bool }
type Name(name) =
member _.Name = name
let p1 = { Name = "Phillip"; Age = 30 }
let p2 = { Name = "Phillip"; Age = 30; IsFunny = false }
let nm = Name "Phillip"
M.printName p1
M.printName p2
M.printName nm
Это позволяет скрыть детали того, как вы «правильно выстроили ограничение», и позволяет легко повторно использовать подпись в других вещах, которые вы хотите опубликовать.
Комментарии:
1. Это потрясающе, но я не понимаю, как имя возвращается из активного шаблона hasName. У вас есть какая-нибудь ссылка, объясняющая этот синтаксис?
2. Это синтаксис «вызова» SRTP. Это фактически говорит: «позовите
HasName
участникаx
«. Но синтаксис, э-э-э, довольно тупой.