2016-02-12 3 views
1

Я новичок в F # и функциональном программировании и нуждаюсь в некоторой помощи. Я прихожу из C#, поэтому мое мышление все еще немного мешает.Как объявить свойство записи как абстрактную функцию

Мне нужно передать некоторые параметры функции, и я использую запись для этого. Один из вариантов - это функциональный блок продолжения -> Опция < 'a>. Я не могу понять, как определить тип записи. Ниже приведен пример того, что я пытался.

type Func2<'a> = 'a -> 'a option 

type ProcessOptions = { 
     func1: int -> int option 
     func2: Func2<int> // This works... 
     //func2: Func2<'a> // ... but this is what I'm trying to achieve - so that I can pass any Func2<'a> using this record. 
    } 

let f1 a = 
    let r = Some a 
    printfn "f1: %A" r |> ignore 
    r 

let f2 (a:'a) = 
    let r = Some a 
    printfn "f2: %A" r |> ignore 
    r 

let f3 (processOptions:ProcessOptions) = 
    processOptions.func1(3) |> ignore 
    processOptions.func2 789 |> ignore 
    () 

let f4 (processOptions:ProcessOptions) = 
    processOptions.func1(4) |> ignore 
    //processOptions.func2 "abc" |> ignore // as a result this does not work... 
    () 

[<EntryPoint>] 
let main argv = 

    f1(1) |> ignore 
    f2 123 |> ignore 
    f2 "abc" |> ignore 

    let fo = { 
     func1 = f1 
     func2 = f2 
    } 
    f3 fo 

    let fo1 = { 
     func1 = f1 
     func2 = f2 
    } 
    f4 fo1 


    0 

ответ

1

член внутри записи не может быть обобщенной функцией (что можно вызвать с различными типами аргументов, таких как int или string). Он всегда будет иметь один фиксированный тип.

Хитрости вы можете использовать, чтобы определить простой интерфейс с общим способом:

type Func = 
    abstract Invoke<'a> : 'a -> 'a option 

Теперь ваши члены в записи могут быть только типа Func (без аргументов универсального типа), но Invoke метод внутри Func будет родовым:

type ProcessOptions = 
     { func1: Func 
     func2: Func } 

Func создания значения немного сложнее, чем писать обычные функции, но вы можете использовать выражение объекта:

let f1 = 
    { new Func2 with 
     member x.Invoke(a) = 
     let r = Some a 
     printfn "f1: %A" r |> ignore 
     r } 

И теперь вы можете обойти ProcessOptions и вызвать метод Invoke с различными типами аргументов:

let f4 (processOptions:ProcessOptions) = 
    processOptions.func1.Invoke 4 |> ignore 
    processOptions.func2.Invoke "abc" |> ignore 

f4 { func1 = f1; func2 = f1 } 
+0

Спасибо Tomas. Мне нравится ваше решение, потому что оно позволяет легко добавлять в запись дополнительные типы функций. Решение Джона также работает, но я думаю, мне придется добавлять более общие типы к ProcessOptions <...> для дополнительных типов. –

1

Здесь вам нужно сделать запись общий - с somehting как

type ProcessOptions<'a> = { 
     func1: int -> int option 

     func2: Func2<'a> // ... but this is what I'm trying to achieve - so that I can pass any Func2<'a> using this record. 
    } 
Смежные вопросы