Помещение: Я думал, что оператор трубопровода - это ничего, кроме синтаксического сахара, поэтому x |> f
должен быть точно таким же, как f(x)
.F # таинственные различия между трубопроводом и функцией применения
Аналогично, я думал, что f (fun x -> foo)
эквивалентно let g = fun x -> foo; f g
Но, видимо, есть различия, которые я не понимаю.
Пример 1:
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ @"\foo\bar.txt")
let fileList = List.ofSeq files
fileList |> List.map (fun f -> TestCaseData(f).SetName(""))
Это прекрасно работает: TestCaseData ожидает arg:obj
который подобран f
в свою очередь, в Inferred быть string
, поскольку fileList
список имен файлов. Однако следующее не работает
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ @"\foo\bar.txt")
let fileList = List.ofSeq files
List.map (fun f -> TestCaseData(f).SetName("")) fileList
Ничего, но последняя строка изменилась. Неожиданно f
выводятся в obj []
и TestCaseData
требует аргумента типа obj []
и, следовательно, я получаю сообщение об ошибке
Error 1 Type mismatch. Expecting a obj [] list but given a string list
The type 'obj []' does not match the type 'string'
я бы подумал, что оба сниппет эквивалентны продукции правильного кода, но только первый делает ?!
Пример 2:
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
Assert.Throws<FatalError> (fun() -> ParsePkg.parse "Dummy path" lexbuf |> ignore)
|> ignore
Над все работает отлично.
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
let ff = fun() -> ParsePkg.parse "Dummy path" lexbuf |> ignore
Assert.Throws<FatalError> (ff)
|> ignore
Как вы видите, все, что я сделал вытащить аргумент утверждения на первом определении let ff = ...
(для удобства понимания, скажем) и вдруг точки компилятора к (ff)
аргумента и жалуется:
Error 2 This expression was expected to have type TestDelegate but here has type unit -> unit
TestDelegate - это тип NUnit, который я использую здесь, и он совпадает с unit->unit
, поэтому я предполагаю, что он будет унифицирован в любом случае, но это даже не имеет значения. Почему вообще возможно, что тип меняется, так как снова я считаю, что сделал чисто синтаксическую замену ?!
Я также хотел бы отметить, что, судя по сообщению об ошибке, функция 'TestCaseData', вероятно, принимает не' obj', но '[] obj []', который работает, когда вы пытаетесь передать ему одиночный 'obj', но получает вывод как' obj [] ', когда тип аргумента еще не известен. –
@FyodorSoikin хорошая точка и обновляется соответственно. спасибо –
Это интересно. Таким образом, действительность программы зависит не только от синтаксиса и (в принципе) от действительного использования типов, но и от существующего в настоящее время механизма вывода типа. Таким образом, данный текст программы может стать действительным/недействительным в зависимости от будущей реализации Microsoft в отношении вывода типа в компиляторе? Я нахожу очень тревожным, что алгебраические законы, такие как '(|>) f x = f x', действительны или недействительны в зависимости от того, какие типы' f' и 'x' имеют. –