마이크로소프트 문서가지고 공부했고
진도는 여기까지 나갔음
개발환경은 온라인 REPL 로 실습 했음
후기
1. 힌들리 밀러 타입시스템 존나 신기함 알아서 다 추론함
2. 패턴매칭. 구조분해 매우 쉽게 됨
3. 파이프 연산자랑 컴포지션 연산자 히트인거 같음
4. 인자 부족하면 자동으로 커링되는거 개쩌는거 같음
1. 비교연산자가 == !=가 아니라 = <> 인게 킹받음
2. module 이 뭔지 잘 모르겠음 네임스페이스로 대충 넘어감
3. 파이프 연산자 |> 는 infix 함수라서 |> a f가 아니라 a |> f 로 쓴다는데 infix 함수로 되는 조건이 뭔지 모르겠음
4. do 바인딩이 뭔지 모르겠음 코틀린 run 함수랑 비슷한거 같긴 함
5. <- 가 정확히 뭔지 모르겠음. 뮤터블 연산할 때 써주는거 같음 (하스켈은 바인드 연산이었던거 같은데 맞나)
6. Union 타입이 있는건지 없는건지 잘 모르겠음 type 키워드로 만드는거 같은데 string | int 형은 못만드는거 같음
7. 기능이 비슷하거나 이름이 비슷한 키워드가 많아서 어지러움
8. class record type 중 어떤걸 어느 상황에 써야하는건지 모르겠음 (특히 클래스의 member 키워드를 써야하는 이유를 젤 모르겠음)
9. 왜 리스트 구조분해할 땐 얘 혼자 :: 쓰는지 모르겠음 (head :: tail)
더 있던거 같은데 퇴근하고 집가서 좀 더 찾아봐야지
파이프는 개인적으로 D언어 UFCS나 하스켈 TDNR이 취향이드라
https://tour.dlang.org/tour/kr/gems/uniform-function-call-syntax-ufcs
https://wiki.haskell.org/TypeDirectedNameResolution
<-는 js에서 await 쓰는 것처럼 모나드를 편하게 쓸수 있도록 해주는거라 생각하면 될듯
근데 await 라고하기엔 아무 실행 컨텍스트 필요없이 뮤터블 값 바꿀 때 썼었음
참고로 TDNR은 하스켈 커뮤니티에서 작명한 개념이지만 하스켈에는 없는 기능이다
<- 모나드는 하스켈 얘기고 f#에서는 뮤터블 연산이 맞음
바로위에 do가 나와서 하스켈이랑 동일한 문법인줄 알았는데 아니었나보구만
f#은 사실상 닷넷-오캐믈이라서 <>나 |> 같은건 ocaml의 유산임
<-는 뮤터블할때 쓰는거 맞고 모듈은 ML계통 언어 한번도 안만져봤으면 씹 어지러울거임 일단은 대강 넘어가셈
오.. 제대로 공부하셨네 ㅋㅋ 참고로 타입추론은 러스트가 더 개쩔긴함 역방향도 가능해서
H-M추론이면 원래 역방향 되는거아님?
러스트는 principal type property도 없다... HM이 조스로 보이냐
미안 내가 말한건 bi-directional type checking이었는데 한글로 하려다보니 이상해졌네
그건 higher rank 애들 지원하려다보니 undecidable해질 수밖에
러스트 타입 시스템이 엄격한 H-M 기반보다 우월하다는 건 아님.. 장작 태울 의도 없음 ㅠ
HM 원본 알고리즘은 bidirectional은 아닌걸로 아는데 HM에 기반한 왠만한 함수형 언어들은 당연히 bidirectional 지원함
러스트는 라이프타임도 있고 훨씬 어려운 문제를 다뤄야 되는건 맞지. 근데 undecidable하다는거 자체가 타입추론이 잘 된다는 말이랑 정 반대 아니냐
다른 함수형 언어는 모르겠는데 본문에서 언급한 fsharp의 경우에는 higher rank 타입에서의 역전파가 안돼서 코딩하다 annotation 달아주는 경우가 생각보다 많더라고. 사실 내가 fsharp을 주력으로 쓰고 있어
애초에 '추론이 잘 된다'를 잘 정의할 수 있을지는 잘 모르겠지만 난 user-friendly한 관점을 주로 얘기한거라서 네 말이 맞다고 생각함
아 higher rank 쓰는거면 네 말도 맞긴 함. 하스켈은 higher rank polymorphism은 기본적으로 꺼져있어서 그거 기준으로 생각했네. 근데 어지간한 코딩에서는 higher rank polymorphism 자주 안필요한데 얼마나 하드하게 쓰는거임
정적 타입 분석기 조그맣게 맹글고 있는데.. 하드하다면 하드한듯
딴소린데 매일같이 정적타입이 좋아요 타입없는 언어 싫어요 이러는 친구들 하는 말을 들어보면 타입 좋다는게 그런 의미가 아닌듯함 C++에서 auto 쓰고 Java에서 var 쓰기만 해도 막 화냄 그냥 user-friendly한 관점이라는 표현을 보고 든 뻘생각임 ㅋ
다른건 대충 댓글에서 언급된 것 같으니 궁금해하시는 것 중 언급 안된 것 위주로 작성함. 2. 일단은 module은 좀 더 specific한 namespace라고 생각하면 됨. module 자체적으로 변수를 가질 수 있고, 따라서 IL에서는 클래스로 번역됨. 3. custom infix operator를 만들고 싶다면 "!, $, %, &, *, +, -, ., /, <, =, >, ?, @, ^, |, ~" 만 포함해서, 그리고 괄호를 쳐서 함수 이름을 작성하면 됨. ex) let (|>) a f = f a 처럼 정의. 4. do는 unit을 리턴하는 함수를 실행시킬 때 쓰는데 사실 대부분의 경우 do를 생략해도 동일함. 6. 가능함. Discriminated union 찾아보셈.
8. type은 union, record, class를 포함한 다른 커스텀 타입을 만들어낼 수 있는 만능 키워드임. record는 여러 데이터를 묶을 때 사용함. class는 OOP에서의 그 클래스랑 동일함. F#은 하스켈과는 달리 멀티 패러다임 언어이므로 이런 OOP스러운 개념 또한 존재하는 거임. 클래스 내에서 let은 만들면 private field, val은 public field이고, member는 public property라고 생각하면 됨.
마지막으로 FP 언어인 F#에서 대놓고 OOP스럽게 나온 이 클래스의 대표적인 사용법은 다음과 같음 1. C#에서도 사용할 것을 전제할 때. C#과 F#은 상호 호환이 잘 되는 언어이므로 F#으로 짜더라도 C#에서의 사용을 염두에 둔다면 클래스로 만드는게 바람직함. 2. Computation Expression(CE)을 직접 만들 때. CE는 모나드 개념을 F#스럽게 구현한 문법이고, 이걸 직접 만들려면 클래스로 만들어야 함. 3. 기타 다른 이유로 Encapsulation 등의 OOP 개념이 필요할 때.