F# - На параметрах передал методам C# - они кортежи или что?

Я много раз читал это

Блоки, сгенерированные от F# или любого другого языка.NET, (почти) неразличимы.

Я тогда экспериментировал с F# и C# interop на.NET 4 (бета 2). Я создал новое решение и проект C#, со следующим классом:

public class MyClass {
    public static int Add(int a, int b) { return a + b; }
}

Затем на проекте F#, после ссылки на проект C#, я попробовал:

MyClsas.Add(4, 5) |> printfn "%d" // prints 9 (no kidding!)

Пока неплохо. Тогда другое предложение, которое я много раз читал (возможно, на различных книгах) прибыло по моему мнению:

Передающие аргументы функциям из других библиотек.NET при использовании синтаксиса как ".MethodName (parm1, parm2)", то есть, параметры передаются как Кортеж.

Добавьте, что к чему-то, на чем я когда-то читал здесь ТАК (но не смог, находят, что это связывается с), по вопросу, где OP пытался создать использование как [ 4, 5, 6 ] (когда он имел в виду [4; 5; 6]):

"Запятая является 'оператором создания кортежа', для всего остального используют точку с запятой".

Тогда я изменил свой класс к следующему:

public class MyClass {
    public static int Add(int a, int b) { return a + b; }
    public static int Add(Tuple<int, int> a) { return a.Item1; }
}

Теперь я пытался использовать его на F#:

MyClass.Add(4, 5) |> printf "%d" // prints ... (keep reading!)

Так, сложение этих трех цитат выше, можно прийти к заключению что:

  • F# создаст Кортеж, когда он будет видеть (4, 5)
  • Тогда это назовет перегрузку Add(Tuple<int, int>)
  • Таким образом, это распечатает 4

К моему удивлению это распечатало 9. Разве это не интересно?

Что действительно происходит здесь? Вышеупомянутые цитаты и это практические наблюдения, кажется, находятся в противоречии. Можно ли выровнять по ширине "обоснование" F#, и возможно указывающий на некоторые документы MSDN если возможный?

Спасибо!

Править

(для добавления большей информации (из ответа Blindy))

Если Вы делаете:

MyClass.Add((4, 5)) |> printfn "%d" // prints 9

F# звонит Add(Tuple<int, int>) перегрузка.

Однако, если Вы создаете другой проект F# (так другой блок) с этим:

namespace MyFSharpNamespace
type MyFShapClass = class
    static member Add x y = x + y
    end

Можно использовать его на C# как это

public static void Main(string[] args) {
    MyFSharpNamespace.MyFSharpClass.Add(4, 5);
}

Пока неплохо. Теперь, когда Вы пытаетесь использовать его от F# (из другого проекта, другого блока), необходимо сделать:

MyFSharpNamespace.MyFSharpClass.Add 4 5 |> printfn "%d"

Если Вы передаете аргументы как (4, 5) F# не скомпилирует потому что Add int -> int -> int, и нет (int * int) -> int.

Что происходит?!?

19
задан Juliet 8 January 2010 в 08:04
поделиться

4 ответа

При передаче аргументов функциям из других библиотек .NET вы используете синтаксис вроде «.MethodName (parm1, parm2)», то есть параметры передаются как кортеж.

Это еще ужаснее. См. Описание разрешения перегрузки метода в спецификации языка .

По сути, в нем говорится, что аргумент при вызове метода на самом деле не кортеж. Это синтаксический кортеж, означающий разделенный запятыми список чего-либо, но круглые скобки являются частью синтаксиса вызова метода, как и запятые. Вот почему, например, o.M (a = 1, b = 2) не является вызовом метода с кортежем из двух логических значений, а скорее с двумя именованными аргументами.

Итак, обычно каждый разделенный запятыми компонент просто отображается в отдельный аргумент. Следовательно, почему Add (1, 2) вызывает перегрузку Add (int, int) , а Add ((1, 2)) вызывает Add ( Кортеж ) . Здесь нет двусмысленности.

Однако в вашем конкретном случае возникает особый случай:

Если нет именованных фактических аргументов и есть только один метод-кандидат в M , принимающий только один не- необязательный аргумент, тогда разложение arg в форму кортежа игнорируется, и есть один с именем фактический arg , который является самим arg .

Итак, когда вы удалили все перегрузки, кроме кортежа, внезапно все, что было внутри круглых скобок, эффективно обрабатывается как конструктор кортежа при вызове. Но если вы, например, иметь две перегрузки, Add (int) и Add (Tuple ) , тогда вызов формы Add (1,2) не будет Решаю вообще.

19
ответ дан 30 November 2019 в 04:29
поделиться

У меня сейчас не установлен F#, но мне кажется, что

MyClass.Add(4, 5) |> printf "%d"

напечатает 9, в то время как

MyClass.Add((4, 5)) |> printf "%d"

напечатает... 4 верно? Обратите внимание на двойные парантезы, внутреннюю пару, обозначающую кортеж, и внешнюю пару, обозначающую вызов функции.

3
ответ дан 30 November 2019 в 04:29
поделиться

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

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

Итак, ваш второй пример создает кортеж F #, помещает его в стек, а затем вызывает перегрузку Add , которая принимает типы, содержащиеся в кортеже.

Во всяком случае, это мое предположение. Предположительно, вы использовали F # больше, чем я, и вы могли бы получить больше информации. Вы также можете получить дополнительные подсказки, посмотрев на сгенерированный код Reflector .

0
ответ дан 30 November 2019 в 04:29
поделиться

Это просто волшебство компилятора.

let add a b = a+b 

add компилирует до add(a,b), облегчая вызов из C#. Тем не менее, F# программы все еще воспринимают его как add(b) из-за атрибута в IL.

При вызове функций C# в F#, может помочь мысль о том, что функция C# имеет только один параметр - кортеж, элементы которого определяют правильную перегрузку. Таким образом, можно писать:

// MyClass.Add(5,3) = 8
let eight = (5,3) |> MyClass.Add
3
ответ дан 30 November 2019 в 04:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: