Я редко сталкиваюсь с этой борьбой в настоящее время с F #, но опять-таки тип наследования гораздо реже встречается с F #, поэтому, возможно, мне просто повезло. Или у меня нет очевидного. Обычно, когда компилятор жалуется на незнание определенного типа, я отменяю порядок труб или композиционных операндов, и я готов.Вывод типа с трубопроводом или композицией завершается с ошибкой, когда нормальный вызов функции преуспевает
В принципе, при вызове функции, который работает как g(f x)
, он также работает как x |> f |> g
или (f >> g) x
. Но сегодня это не ...
Вот неаккуратно понятие доказательства правильности того, что я имею в виду:
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
Обычно, это работает (по крайней мере в моем опыте). Линии с «откатом» броска:
ошибка FS0001: несоответствие типа. Ожидание MyExc -> 'a, но с учетом exn -> Ex. Тип «MyExc» не соответствует типу «EXN»
Не большое дело, не трудно обойти, но я, случается, приходится писать много кода, где композиция является проще/очиститель подход и я не хочу писать кучу полезных функций, которые я должен использовать везде.
Я рассмотрел гибкие типы, так как я предполагаю, что это проблема контравариантности, но я не вижу, как я могу применить ее здесь. Любые идеи сохранить эту идиоматику?
Обратите внимание, что если я перестраиваю, т. Е. Как Ex <<createExc>> Fail
или используя оператор обратной трубы, я получаю ту же ошибку в другой части.
Отлично и проницательно, как всегда, спасибо Томасу. Похоже, мы согласны с тем, что это, безусловно, странное поведение. Я всегда думал (и, как правило, это правильно), что конструкторы DU ведут себя как функции, и я все время цепляю/составляю их. Глядя на подпись членов DU, они «выглядят» как функции. – Abel