Rzadko mam tę walkę w dzisiejszych czasach z F #, ale potem znowu typ dziedziczenia jest o wiele mniej powszechny w przypadku F #, więc może po prostu miałem szczęście. Albo brakuje mi tego, co oczywiste. Zwykle, gdy kompilator narzeka, że nie zna określonego typu, odwracam kolejność potoków lub operandów kompozycji i gotowe.Wnioskowanie typu z orurowaniem lub kompozycją nie udaje się, gdy normalne wywołanie funkcji się powiedzie
Zasadniczo, biorąc pod uwagę wywołanie funkcji, które działa jako g(f x)
, działa również jako x |> f |> g
lub (f >> g) x
. Ale dziś nie robi ...
Oto koncepcja proof-of-brudny, co mam na myśli:
module Exc =
open System
type MyExc(t) = inherit Exception(t)
let createExc t = new MyExc(t)
type Ex = Ex of exn
type Res = Success of string | Fail of Ex with
static member createRes1 t = Ex(createExc(t)) |> Fail // compiled
static member createRes2 t = t |> createExc |> Ex |> Fail // FS0001
static member createRes3 = createExc >> Ex >> Fail // FS0001
Normalnie, to działa (przynajmniej z mojego doświadczenia). Linie z rzutem "nieudanym":
błąd FS0001: Niezgodność typu. Oczekiwanie na MyExc -> 'a ale biorąc pod uwagę -> Ex. Typ „MyExc” nie pasuje do typu „exn”
Nic wielkiego, nie trudno się obejść, ale zdarza mi się napisać dużo kodu w których skład jest łatwiejsze/sprzątaczka podejście i ja nie chcę napisać paczki funkcji użytkowych, które muszę umieścić wszędzie.
Spojrzałem na elastyczne typy, jak sądzę, jest to problem kontrawariancji, ale nie widzę, jak mogę go zastosować tutaj. Jakieś pomysły na zachowanie tego idiomatycznego?
Uwaga, jeśli przestawię, tj. Jako Ex <<createExc>> Fail
lub za pomocą operatora cofania, kończę z tym samym błędem na innej części.
Doskonały i wnikliwy, jak zawsze, dzięki Tomas. Wygląda na to, że zgadzamy się, że to z pewnością dziwny rodzaj zachowania. Zawsze myślałem (i zwykle to jest poprawne), że konstruktory DU zachowują się jak funkcje i cały czas je łączę/komponuję. Patrząc na podpis członków DU, wyglądają jak "funkcje". – Abel