Вызов кода F# из C#
Я играю с F# и C#, и хотел бы вызвать F# код из C#.
мне удалось заставить его работать наоборот в Visual Studio, имея два проекта в одном решении и добавив ссылку на код C# в проект F#. После этого я мог бы вызвать код C# и даже пройти через него во время отладки.
то, что я пытаюсь сделать, это код F# из C# вместо кода C# из F#. Я добавил ссылку на проект F# в C# проект, но он не работает так, как это было раньше. Я хотел бы знать, если это возможно, не делая это вручную.
4 ответов:
(EDIT: я изначально связался с этими файлами извне, но мой хост SVN больше не позволяет анонимный доступ. Таким образом, код теперь встроен в этот ответ.)
Ниже приведен рабочий пример вызова F# из C#.
Как вы столкнулись, я не смог добавить ссылку, выбрав из "добавить ссылку ... Вкладка "проекты". Вместо этого мне пришлось сделать это вручную, перейдя к сборке F# в разделе "Добавить ссылку ... Вкладка "Обзор".
- - - - - - F# Модуль - - - - -
// 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# ДЛЯ МОДУЛЯ - - - - -
// 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); } } }
Он должен "просто работать", хотя вам, возможно, придется построить проект F# перед ссылкой проекта на проект из C# works (я забыл).
общий источник проблем-пространства имен / модули. Если ваш код F# не начинается с объявления пространства имен, он помещается в модуль с тем же именем, что и имя файла, так что, например, из C# ваш тип может отображаться как "программа.Foo", а не просто "Foo" (если Foo-это тип F#, определенный в программе.файловая система.)
С этой ссылке они, кажется, имеют ряд возможных решений, но тот, который казался самым простым, был комментарий:
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 -> intC# Код:
int a = Module1.f3(Module1.f2, 10, 20); // method gets converted to the delegate automatically in C#
// тест.ФС :
module meGlobal type meList() = member this.quicksort = function | [] -> [] // if list is empty return list | first::rest -> let smaller,larger = List.partition((>=) first) rest List.concat[this.quicksort smaller; [first]; this.quicksort larger]// тест.cs:
List<int> A = new List<int> { 13, 23, 7, 2 }; meGlobal.meList S = new meGlobal.meList(); var cquicksort = Microsoft.FSharp.Core.FSharpFunc<FSharpList<IComparable>, FSharpList<IComparable>>.ToConverter(S.quicksort); FSharpList<IComparable> FI = ListModule.OfSeq(A.Cast<IComparable>()); var R = cquicksort(FI);
Comments