3

나는 F #으로 시작하여 구문을 이해하는데 약간의 진전을 보였다. 그러나 F #의 기능을 사용하는 가장 좋은 방법에 대해서는 아직 명확하지 않습니다. 파이썬에서 내가 어디에서 왔는지, 일반적으로 일을하는 "최고의"(거의 표준적인) 방법이있다. 어쩌면 F #의 경우이기도하지만 알아 내지 못했습니다. 그래서 아래 질문은 F #을 사용하는 가장 좋은 방법이며, F #의 구문에 대한 기술적 인 질문은 아닙니다.Intellisense를 활용하는 코드를 작성해야합니까?

최근 메이어 박사가 OOP의 점 표기법을 칭찬하면서 Intellisense가 사용 가능한 방법 목록을 표시 할 수 있음을 알게 된 Dr. Eric Meijer (C9 Lectures - Functional Programming Fundamentals Chapter 2 of 13)의 비디오를 보았습니다. 그는 순수 FP에서 이러한 기능을 사용할 수 없으므로 프로그래머가 "앞으로 나아갈 수 있도록"프로그램을 훨씬 쉽게 만들 수 있음을 시인합니다.

실험적인 비트는 Intellisense가 F # 클래스와 함께 작동하지만 물론 클래스처럼 도트 표기법을 사용하는 F # 레코드에서도 작동 함을 보여줍니다. 이것은 Intellisense를 활용하여 클래스를 작성하지 않고도 코드를 작성할 수 있음을 의미합니다 (F # 클래스에서는 레코드보다 무겁고 느리다는 가정하에 잘못 입력 한 경우 수정하십시오). 레코드 유형을 만드는 :

// Create a record type with two values that are functions of two arguments 
type AddSub = {add2: int -> int -> int; sub2: int -> int -> int} 

// Instantiate a record 
let addsub a = 
    {add2 = (fun x y -> a + x + y); sub2 = (fun x y -> a - x - y)} 

// Returns 7, Intellisense works on (addsub 0). 
(addsub 0).add2 3 4 
// Returns 3, Intellisense works on (addsub 10). 
(addsub 10).sub2 3 4 

// Create two functions of three arguments 
let add3 a x y = a + x + y 
let sub3 a x y = a - x - y 

// Also got 7, no Intellisense facility here 
add3 0 3 4 
// Also got 3, no Intellisense facility here 
sub3 10 3 4 

이 순수한 FP와 OOP의 중간 전략이 있음을 보여줍니다

다음 코드는 동일한 작업을 수행하는 코드를 작성하는 두 가지 방법을 ("버전"그들에게 전화)를 보여줍니다 위와 같이 함수 값을 사용합니다. 이러한 전략은 객체 (레코드 인스턴스)에 중점을 둔 의미있는 단위로 코드를 구성하고 Intellisense를 사용할 수있게하지만 상속 및 하위 클래스 다형성과 같은 클래스에서 제공하는 기능 중 일부가 부족합니다.

OOP 배경에서 나는 위의 코드에서 a과 같은 객체가 매개 변수 x 및 y보다 어떻게 든 "중요"하다고 (나는 정의하지 않은 채로 남겨 둘 것입니다) 이러한 코딩 전략이 정당화 될 수 있다고 생각합니다. 코드 조직 및 Intellisense 사용 기능을 근거로합니다. 반면에 OOP의 복잡성으로 인해 불타 버린 나는 "순수한"FP 영역에 남아있을 것입니다.

두 가지 극단적 인 대안 (OOP 및 순수 FP)간에 레코드 사용이 가치가있는 타협입니까?

대체로 다른 대안보다 선호되는 상황에 대한 일반적인 지침은 무엇인가? (순수 FP, 위와 같은 기록 또는 클래스)?

마지막으로 내 코드를 구성하고 Intellisense를 활용하는 데 도움이되는 다른 코딩 전략이 있습니까?

답변

8

Intellisense는 여전히 F #에서 잘 작동하지만 클래스 수준이 아닌 모듈 수준에서 작동합니다. 즉, 난 그냥 List.에 입력 내가 (F # 인텔리을 제공하는 Ionide 플러그인과) 점, VS 코드를 입력하면 나에게 가능한 완성의 목록 주었다 append, average, averageBy, choose, chunkBySize ...

로를 자신의 기능에서 그 혜택을받을 모듈에 넣어 :

module AddSub = 
    let add2 x y = x + y 
    let sub2 x y = x - y 
    let add3 a x y = a + x + y 
    let sub3 a x y = a - x - y 

을 이제 AddSub.를 입력 할 때, 당신은 점을 입력 한 후, 인텔리 가능 followups로 add2, add3, sub2sub3을 제안합니다. 그러나 "적절한"F # 스타일로 기능을 "깨끗하게"유지할 수 있습니다.

마지막으로 기능 디자인에 대한 조언을 한 장 더 제공합니다. 하나의 매개 변수 (예 : add3sub3 함수의 a)가 다른 매개 변수보다 "중요"하다는 것을 언급했습니다. 즉 당신이 그렇게처럼 |> 연산자를 사용하여 함수 체인에 넣을 수 있기 때문에 F #으로, 이러한 매개 변수는 아마의 마지막 매개 변수를해야한다 : 스타일을 사용하여, 오히려

let a = 20 
a |> AddSub.add3 5 10 |> AddSub.sub3 2 3 // Result: 30 

또는 대부분의 사람들 하나의 시작 값에서 작업의 "파이프 라인"있을 때 선호 : 그것은 더 많은 작업이있을 때

let a = 20 
a 
|> AddSub.add3 5 10 
|> AddSub.sub3 2 3 
// Result: 30 

파이프 라인을 안감 수직으로 더 중요합니다. 내 경험에 따르면 파이프 라인에 두 개 이상의 "추가"매개 변수가 지정되면 위의 파이프 라인에는 add3sub3 함수에 각각 두 개의 "추가"매개 변수가 있고 두 개의 "추가"매개 변수가있는 경우, 매개 변수가 단일 값보다 복잡하면 (예 : 하나의 매개 변수가 (fun x -> sprintf "The value of x was %d" x) 또는 이와 같은 일부 익명 함수 인 경우) 수직으로 정렬해야합니다.

P. 아직 읽지 않았다면 Scott Wlaschin의 우수 시리즈 Thinking Functionally을 읽으십시오. 이 답변에 대한 많은 것들을 설명하는 데 도움이 될 것입니다. 왜 "가장 중요한"논증을 마지막에 넣는 것이 좋습니다. |> 매개 변수와 함께 사용하는 방법에 대한 간단한 설명을 즉시 이해하지 못했거나이 대답에 대해 의문의 여지가있는 사항이 있으면 Scott의 기사에서 많은 이점을 얻습니다 .

+0

굉장! 감사. 나는 모듈을 생각해야했다. 나는 Meijer 박사가 Intellisense를 사용할 수 없다는 불만을 토로했다는 것을 알았습니다. 그러나 그는 하스켈에 대해 이야기하고 있었고 아마 하스켈에 모듈이나 이와 유사한 시설이 없었을 것입니다. – Soldalma

+0

하스켈의 표준 관습은 자격을 갖춘 모듈을 사용하는 대신 모듈에서 함수를 가져 오는 것이므로 Intellisense와 친숙하지는 않습니다. – Tarmil

+0

@ Tarmil afaik, Haskell에 대한 자동 완성 도구가 있습니다. https://github.com/rikvdkleij/intellij-haskell – Yawar

3

귀하의 질문은 꽤 광범위하며 모듈의 특정 측면은 이미 @munn에서 다루어졌습니다. 나는 변화하는 팀의 개발자들과 함께 꽤 큰 F # 코드베이스에서 내 자신의 작업으로 인해 발생하는 몇 가지 생각들을 추가하고 싶었다.

코드 검색 가능성 규칙. Intellisense를 통해 객체에 사용할 수있는 메소드를 볼 수있게되면 코드베이스가 커짐에 따라 점점 더 중요 해지고 있습니다. 하지만 더 중요한 것은 팀에 새로 가입 한 사람들을 도울 수 있습니다.이 사람은 모듈/X에 클래스/레코드/인스턴스의 인스턴스로 작업 할 수있는 모든 메소드가 있음을 아직 모르고있을 수 있습니다.

나는 F# component design guide 매우 도움이됨을 발견했습니다. OOP와 기능 간의 균형을 유지하는 방법에 대한 자세한 내용을 제공합니다.

이 유형의 고유 작업에 사용할 속성과 메서드를 수행합니다 : 그것은 직접 당신이 제기 된 점을 참조 말한다 어디 특정 질문 들어, section on intrinsic operations를 참조하십시오. 함수 프로그래밍 배경의 일부 사람들은 객체 지향 프로그래밍을 함께 사용하지 않아서 형식과 관련된 내장 함수를 정의하는 함수 세트 (예 : foo.Length가 아닌 foo 길이)를 포함하는 모듈을 선호하기 때문에이 함수가 특별히 호출됩니다. 그러나 다음 글 머리도 보아라. 일반적으로 F #에서는 객체 지향 프로그래밍을 소프트웨어 공학 장치로 사용하는 것이 좋습니다. 이 전략은 또한 Visual Studio의 "Intellisense"기능과 같은 도구를 사용하여 개체를 "점으로 찍어"유형별 메서드를 검색 할 수 있습니다.

클래스 계층 구조를 작성하려고 할 때 상속을 차별화 된 공용체 유형으로 바꿀 수 없는지 두 번 생각하십시오.가능한 한 레코드, 수업 등으로 멤버 (정적 또는 인스턴스 멤버)를 추가 할 수 있습니다.

type Animal = 
    | Cat | Dog 
    member this.Sound = match this with | Cat -> "meow" | Dog -> "bark" 
    static member FromString s = function | "cat" -> Cat | "dog" -> Dog | _ -> failwith "nope." 
+3

Imho, 형식을 최대한 단순하게 유지하고 형식과 그 연산 함수를 같은 형식으로 함께 넣는 것이 좋습니다 모듈을 유지하고 모듈을 주요 유형에 집중적으로 집중시킵니다. 그런 다음 OOP와 FP 스타일을 어색하게 전환하는 대신 모든 곳에서 기능을 사용하는 방법을 고수합니다. 예 : https://gist.github.com/yawaramin/552c25a23549f15556d54954e39f946d – Yawar

+0

@Anton - 통찰력에 감사드립니다. 나는 당신이 인용 한 조언에 조금 놀랐다 고 고백한다. 실용적인 관점에서 볼 때 현명하게 들리지만, FP에는 현명한 대안이있을 것으로 기대했습니다. 클래스 계층 구조에서 확실하지 않습니다. 나는 전문가가 아니지만, 새로운 동물 (라이온/포효)이 등장 할 때마다 동물 유형을 수정해야하는 것처럼 보입니다. 나는 이것이 SOLID의 개방/폐쇄 원칙에 위배된다고 생각한다. 그래도 새로운 하위 유형의 가능성이 없다는 것을 알게되면 작동 할 것입니다. – Soldalma

관련 문제