82 votes

Appelez le code F # à partir de C #

Je joue avec F# et C#, et voudrais appeler le code F# C#.

J'ai réussi à le faire fonctionner dans l'autre sens dans Visual Studio en avoir deux projets dans la même solution, et ajout d'une référence de code C# F# du projet. Après avoir fait cela, je pouvais l'appeler du code C# et même à travers elle pendant le débogage.

Ce que j'essaie de faire est de code F# C# au lieu de code C# F#. J'ai ajouté une référence pour le projet F# C# du projet, mais il ne fonctionne pas comme il le faisait avant. Je voudrais savoir si cela est possible sans le faire manuellement.

59voto

Eric Points 5994

(EDIT: j'avais initialement lié à ces fichiers à l'extérieur, mais mon SVN de l'hôte n'autorise plus l'accès anonyme. Donc le code est maintenant en ligne dans cette réponse.)

Ci-dessous est un exemple de travail de l'appel de F# C#.

Comme vous l'avez rencontré, je n'étais pas en mesure d'ajouter une référence en sélectionnant "Ajouter une Référence ... Projets" onglet. Au lieu de cela j'ai eu à le faire manuellement, en parcourant le F# assemblée dans le "Ajouter une Référence ... Parcourir" onglet.

------ F# MODULE -----

// First implement a foldl function, with the signature (a->b->a) -> a -> [b] -> a
// Now use your foldl function to implement a map function, with the signature (a->b) -> [a] -> [b]
// Finally use your map function to convert an array of strings to upper case
//
// Test cases are in TestFoldMapUCase.cs
//
// Note: F# provides standard implementations of the fold and map operations, but the 
// exercise here is to build them up from primitive elements...

module FoldMapUCase.Zumbro
#light


let AlwaysTwo =
   2

let rec foldl fn seed vals = 
   match vals with
   | head :: tail -> foldl fn (fn seed head) tail
   | _ -> seed


let map fn vals =
   let gn lst x =
      fn( x ) :: lst
   List.rev (foldl gn [] vals)


let ucase vals =
   map String.uppercase vals

----- C# TESTS UNITAIRES POUR LE MODULE -----

// Test cases for FoldMapUCase.fs
//
// For this example, I have written my NUnit test cases in C#.  This requires constructing some F#
// types in order to invoke the F# functions under test.


using System;
using Microsoft.FSharp.Core;
using Microsoft.FSharp.Collections;
using NUnit.Framework;

namespace FoldMapUCase
{
    [TestFixture]
    public class TestFoldMapUCase
    {
        public TestFoldMapUCase()
        {            
        }

        [Test]
        public void CheckAlwaysTwo()
        {
            // simple example to show how to access F# function from C#
            int n = Zumbro.AlwaysTwo;
            Assert.AreEqual(2, n);
        }

        class Helper<T>
        {
            public static List<T> mkList(params T[] ar)
            {
                List<T> foo = List<T>.Nil;
                for (int n = ar.Length - 1; n >= 0; n--)
                    foo = List<T>.Cons(ar[n], foo);
                return foo;
            }
        }


        [Test]
        public void foldl1()
        {
            int seed = 64;
            List<int> values = Helper<int>.mkList( 4, 2, 4 );
            FastFunc<int, FastFunc<int,int>> fn =
                FuncConvert.ToFastFunc( (Converter<int,int,int>) delegate( int a, int b ) { return a/b; } );

            int result = Zumbro.foldl<int, int>( fn, seed, values);
            Assert.AreEqual(2, result);
        }

        [Test]
        public void foldl0()
        {
            string seed = "hi mom";
            List<string> values = Helper<string>.mkList();
            FastFunc<string, FastFunc<string, string>> fn =
                FuncConvert.ToFastFunc((Converter<string, string, string>)delegate(string a, string b) { throw new Exception("should never be invoked"); });

            string result = Zumbro.foldl<string, string>(fn, seed, values);
            Assert.AreEqual(seed, result);
        }

        [Test]
        public void map()
        {
            FastFunc<int, int> fn =
                FuncConvert.ToFastFunc((Converter<int, int>)delegate(int a) { return a*a; });

            List<int> vals = Helper<int>.mkList(1, 2, 3);
            List<int> res = Zumbro.map<int, int>(fn, vals);

            Assert.AreEqual(res.Length, 3);
            Assert.AreEqual(1, res.Head);
            Assert.AreEqual(4, res.Tail.Head);
            Assert.AreEqual(9, res.Tail.Tail.Head);
        }

        [Test]
        public void ucase()
        {
            List<string> vals = Helper<string>.mkList("arnold", "BOB", "crAIg");
            List<string> exp = Helper<string>.mkList( "ARNOLD", "BOB", "CRAIG" );
            List<string> res = Zumbro.ucase(vals);
            Assert.AreEqual(exp.Length, res.Length);
            Assert.AreEqual(exp.Head, res.Head);
            Assert.AreEqual(exp.Tail.Head, res.Tail.Head);
            Assert.AreEqual(exp.Tail.Tail.Head, res.Tail.Tail.Head);
        }

    }
}

27voto

Brian Points 82719

Cela devrait "fonctionner", bien que vous deviez peut-être créer le projet F # avant qu'une référence de projet à projet à partir de C # fonctionne (j'oublie).

Les espaces de noms / modules sont une source commune de problèmes. Si votre code F # ne commence pas par une déclaration d'espace de nom, il est placé dans un module portant le même nom que le nom de fichier, de sorte que, par exemple, du type C # pourrait apparaître sous la forme "Programme.Foo" plutôt que "Foo" (si Foo est un type F # défini dans Program.fs).

6voto

Chris Bunch Points 25857

De ce lien, ils semblent avoir un certain nombre de solutions possibles, mais celle qui semblait la plus simple était ce commentaire :

Code F #:

 type FCallback = delegate of int*int -> int;;
type FCallback =
  delegate of int * int -> int

let f3 (f:FCallback) a b = f.Invoke(a,b);;
val f3 : FCallback -> int -> int -> int
 

Code C #:

 int a = Module1.f3(Module1.f2, 10, 20); // method gets converted to the delegate automatically in C#
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X