C #에서 F # 코드 호출


80

F # 및 C #을 가지고 놀고 있는데 C #에서 F # 코드를 호출하고 싶습니다.

동일한 솔루션에 두 개의 프로젝트를 포함하고 F # 프로젝트에 C # 코드 참조를 추가하여 Visual Studio에서 다른 방식으로 작동하도록 관리했습니다. 이렇게하면 C # 코드를 호출하고 디버깅하는 동안 단계별로 실행할 수도 있습니다.

내가하려는 것은 F #의 C # 코드 대신 C #의 F # 코드입니다. F # 프로젝트에 대한 참조를 C # 프로젝트에 추가했지만 이전 방식으로 작동하지 않습니다. 수동으로 수행하지 않고도 이것이 가능한지 알고 싶습니다.


9
특정 문제가없는 한 C # 프로젝트에서 F # 프로젝트에 대한 참조를 추가하면 현재 "그냥 작동"합니다. .NET 아키텍처 (언어 불가지론, MSIL 등)의 근본적인 약속 또는 이점 중 하나이기 때문에 여기에 특별한 것은 없습니다. 사실 그 반대는 이상 할 것입니다. 이 현상금에 대해 무엇을 더 기대하십니까?
Simon Mourier

답변:


57

다음은 C #에서 F #을 호출하는 작업 예제입니다.

만났을 때 "참조 추가 ... 프로젝트"탭에서 선택하여 참조를 추가 할 수 없었습니다. 대신 "참조 추가 ... 찾아보기"탭에서 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);
        }

    }
}

1
감사합니다. " '참조 추가 ... 찾아보기'탭에서 F # 어셈블리를 검색하여 수동으로 수행해야했습니다." 나를 위해 일한 것입니다.
ZeroKelvin

27

C #의 프로젝트 간 참조가 작동하기 전에 F # 프로젝트를 빌드해야 할 수도 있지만 '그냥 작동'해야합니다 (잊었습니다).

일반적인 문제 원인은 네임 스페이스 / 모듈입니다. F # 코드가 네임 스페이스 선언으로 시작하지 않으면 파일 이름과 동일한 이름의 모듈에 배치됩니다. 예를 들어 C #에서는 형식이 "Foo"가 아닌 "Program.Foo"로 나타날 수 있습니다 (Foo 인 경우 Program.fs에 정의 된 F # 형식).


2
모듈 이름에 대한 정보에 감사드립니다 :).
ZeroKelvin

2
그래, 블로그에 글을 써야하는데 많은 혼란이 생깁니다.
Brian

Fsharp 프로젝트 (dll을 참조의 발전기)가 CSHARP (소비자 프로젝트)와 같은 솔루션에있을 때 추가 문제는, 트리거
조지 Kargakis

6

에서 이 링크 들은 가능한 솔루션 수 있지만, 간단한 코멘트했다 듯 한 것 같다 :

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

C # 코드 :

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

val 행에 오류가 발생했습니다. val f3 : FCallback-> int-> int-> int "오류 1 정의에 예기치 않은 키워드 'val'이 있습니다.이 시점 또는 다른 토큰 이전에 불완전한 구조화 된 구조가 필요합니다."
Tom Stickel 2011

4

// Test.fs :

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]

// Test.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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.