Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Play2
- 파이썬 강좌
- 스칼라 강좌
- 하이퍼레저 패브릭
- 주키퍼
- 스위프트
- 그라파나
- 파이썬 동시성
- Play2 로 웹 개발
- 스칼라 동시성
- Akka
- 이더리움
- 파이썬 데이터분석
- 하이브리드앱
- Golang
- play2 강좌
- play 강좌
- 플레이프레임워크
- 파이썬 머신러닝
- 안드로이드 웹뷰
- 파이썬
- Adapter 패턴
- Actor
- 엔터프라이즈 블록체인
- akka 강좌
- Hyperledger fabric gossip protocol
- CORDA
- hyperledger fabric
- 스칼라
- 블록체인
Archives
- Today
- Total
HAMA 블로그
여러언어를 통해본 함수형 스타일 ( 함수포인터,함수자,람다 ) 본문
2편. 여러언어를 통해본 함수형 스타일 ( 함수포인터,함수자,람다 )
본글은 멀 주장하거나 전문적인 글이 아니라, 정보를 공유하기위한 모음글입니다.
시간이 될때 관심이 있으면 편하게 읽어보시면 될듯합니다. 같이 익숙해져가는게 목표입니다.
먼가를 주장하는글은 1편 언어에서의 강력함과 대중성 그리고 스칼라 http://okky.kr/article/275634 에 있습니다. 참고로 함수형이라는 말에는 다양한 개념들이 있으나 이 글에서는 함수를 매개변수로 넘기는 스타일들부터 익숙해지자는것에 한정되있습니다.
함수 포인터의 정의는 전달가능한 행위의 시작위치! 라고 말할수있으며 사용이유로는
아래와 같이 3가지정도를 말할수있을듯 합니다. 1번이 가장 핵심이구요 .
람다도 마찬가지로 지연호출이 핵심중 하나입니다.
1. 호출시점 유연화.
2. struct 에서 행위를 포함할수있게함
3. 디펜던시 문제 해결.
4. 코딩 단순화로 인한 사고 단순화
4. 코딩 단순화로 인한 사고 단순화
예제 in C )
#include <stdio.h>
void apple(void)
{
printf("apple");
};
int main()
{
void (*fptr)(void); // 선언
fptr = apple; // 대입
fptr(); // 호출
someFunction(fptr); // 매개변수로 넘김.
}
fptr 는 행위 (애플이라고 프린팅하는) 를 가르키고있습니다.
행위를 함수의 매개변수로 넘겨서 다른곳(someFunction)에서 그 행위에 대한 책임을 지도록 합니다.
예제 in C++ )
#include <iostream>
using namespace std;
class fruit
{
public:
void apple()
{
cout << "apple" << endl;
}
void berry()
{
cout << "berry" << endl;
}
};
int main()
{
fruit x, *y;
void (fruit::*f)(void); // 선언
f = &fruit::apple; // 대입
(x.*f)(); // 호출
f = &fruit::berry;
y = new fruit;
(y->*f)();
delete y;
}
C 에는 없는 클래스라는 개념을 가지고있는 C++
클래스의 멤버함수를 가르키는 방법입니다. 객체를 가르키는 방법에 따라 다르기때문에 복잡합니다.
헤깔리기때문에 보통 사용할때 구글링으로 확인합니다.
예제 in C++ with boost)
class CHello
{
void Say()
{
print(“hello”);
}
};
Void func1()
{
CHello hello; // CHello 의 객체 선언
boost::function< void ( void ) > memfunc; // boost::function 객체 선언
memfunc = boost::bind( &CHello::DebugOut, hello, _1 ); // DebugOut 함수를 func 에 바인딩
func2(memfunc);
}
Void func2(boost::function< void ( void ) > _func)
{
_func( 5 ); // CHello::Say() 가 호출!!! 1. 행위를 하게함. ( observer 패턴)
// 2. 호출위치를 조절할수도 있고
// 3. 다른모듈에서 CHello를 호출.(디펜던시문제)
}
위에는 클래스에 대한 멤버함수를 포인팅하는 방법을 좀더 쉽게 하기위해서
비표준 라이브러리에서 function과 bind가 사용되었습니다.근데 진짜 저게 더 쉬워진걸까?
역시 쓸때마다 구글링합니다.
예제 in C++ 11)
#include <iostream>
#include <functional>
using namespace std;
int add(int a, int b) {
return a + b;
}
int main() {
auto f = bind(add, 1, 2);
cout << f() << "\n";
}
///////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <functional>
using namespace std;
using namespace std:placeholders;
int add(int a, int b) {
return a + b;
}
int main() {
auto add1 = bind(add, 1, _1);
cout << add1(100) << "\n";
}
자. c++11 에 와서 boost 라는 비표준라이브러리를 안쓰고 표준라이브러리를 사용하면서
조금 깔끔해졌습니다. auto의 등장
예제 in C++ 11 이전 )
boost::asio::ip::tcp::acceptor m_acceptor;
void handle_accept(Session* pSession, const boost::system::error_code& error)
{
if (!error)
{
std::cout << "클라이언트 접속 성공" << std::endl;
pSession->PostReceive();
}
}
m_acceptor.async_accept( m_pSession->Socket(),
boost::bind(&TCP_Server::handle_accept, // 함수 객체를 넘긴다. (함수포인터넘겨도됨)
this,
m_pSession,
boost::asio::placeholders::error)
);
예제 in C++ 11 이후)
boost::asio::ip::tcp::acceptor m_acceptor;
m_acceptor.async_accept( m_pSession->Socket(),
[this](boost::system::error_code error) // 람다식을 넘김!!
{
if (!error)
{
std::cout << "클라이언트 접속 성공" << std::endl;
m_pSession->PostReceive();
}
StartAccept();
}
);
C++도 11 버전 (2011년) 이전에는 함수자 or 서술자를 쓸때 그것들의 위치가 실제 사용되는 함수와
거리가 멀어지는 문제점때문에 쓰기 꺼렸었지만, 11 버전 이후에 람다가 표준이 되면서 좀 더 많이 사용될것이라고 생각됩니다.
예제 in JAVA)
Public void foo()
{
final int n = 1;
Class ActionListener()
{
Pubic void actionPerformed(Action e)
{
System.out.pringln(“Clicked! N =” +n);
}
}
ActionListener ac = new ActionListener()
Jbutton button = new Jbutton(“Click me”);
button.addActionListener(ac);
}
자바 내부클래스입니다.
final int n = 1; 여기서 n 이 내부클래스에서 참조되는게 중요한데..
저게 바로 클로저라고 하죠. 내부에서 외부의 존재를 참조하는것!!
다만 final 이 꼭 붙어야해서 클로저가 아니다라는 말도 합니다.
예제 in JAVA) 익명클래스
Public void foo()
{
final int n = 1;
Jbutton button = new Jbutton(“Click me”);
button.addActionListener(new ActionListener()
{
Pubic void actionPerformed(Action e)
{
System.out.pringln(“Clicked! N =” +n);
}
});
}
ActionListener 클래스가 함수매개변수로 바로 만들어져 삽입된다.
예제 in JAVA 8 with lamda )
Public void foo() { final int n = 1; Jbutton button = new Jbutton(“Click me”); button.addActionListener( ()-> System.out.pringln(“Clicked! N =” +n);
); }
자바는 함수를 따로 만드는게 언어철학차원에서 지원하지 않기때문에 C++보다 내부 구현에 복잡해질 여지가 많아보입니다. 어설프게 타언어 장점 가져올바에는 일관성을 지키는게 훨씬 낫겠지요.
예제 in C# with delegate)
//대리자 선언
public delegate void SayHandler(string mag);
[1]익명메서드 : Say 함수를 작성하지 않고 익명메서드로 작성
SayHandler hi = delegate(string msg)
{
Console.WriteLine(msg);
};
hi("익명메서드");
//[2]익명메서드 : Button의 click event를 익명 메서드로 작성
Button button = new Button();
button.Click += delegate(string msg)
{
Console.WriteLine(msg);
};
button.OnClick("이벤트 익명메서드");
//[3]람다표현식 : Button의 click event를 Ramda 표현식으로 작성
Button button1 = new Button();
button1.Click += (string msg) => Console.WriteLine(msg);
button.OnClick("람다 표현식");
C# 도 1버전부터 4버전까지 계속 대리자(함수포인터 , 람다) 가 발전되어져 왔다.
예제 in Scala with lamda)
스칼라에서 함수표현
def max(m: Int, n: Int): Int = if(m > n) m else n
스칼라에서의 람다식
1) 보통
def bubbleSort(arr: Array[Int], order: (Int, Int) => Boolean): Unit {
...
val o: Boolean = order(a, b)
...
}
val arr: Array[Int] = Array(2, 5, 1, 7, 8)
bubbleSort(arr, (a: Int, b: Int) => a > b)
2) 짧게
val arr = Array(2, 5, 1, 7, 8)
bubbleSort(arr, (a, b) => a > b)
3) 더 짧게
val arr = Array(2, 5, 1, 7, 8)
bubbleSort(arr, (_: Int) > (_: Int))
4) 가장 짧게
val arr = Array(2, 5, 1, 7, 8)
bubbleSort(arr, _ > _)
예제 in Scala vs JAVA8 with lamda)
JAVA8 )
List names = Arrays.asList("1", "2", "3");
Stream lengths = names.stream().map(name -> name.length());
Scala )
val names = List("1", "2", "3")
val lengths = names.map(name => name.length)
JAVA8 )
List<Photo> photos = Arrays.asList(...)
List<Photo> output = photos.filter(p -> p.getSizeInKb() < 10)
Scala )
val photos = List(...)
val output = photos.filter(p => p.sizeKb < 10)
예제 in javascript)
function applyOperation(a, b, operation)
{
return operation(a,b);
}
function add(a,b) { return a+ b; }
applyOperation(1,2, add);
// anonymous inline function
applyOperation(4,7, function(a,b) {return a * b})
예제 in Ruby with lamda)
class Array
def iterate!(code)
self.each_with_index do |n, i|
self[i] = code.call(n)
end
end
end
array = [1, 2, 3, 4]
array.iterate!(lambda { |n| n ** 2 })
puts array.inspect
# => [1, 4, 9, 16]
예제 in JAVA ) 12보다 큰 단어의 워드카운팅.
int count = 0;
for(String w : words){
if (w.length > 12 ) count++;
}
머하는지 일단 읽어봐야하고 혹시 index 증감으로 배열참조하다보면 오류생길가능성도 조금 더 있겠지만
깔끔하고 너무나 익숙하다.
예제 in JAVA 8 with lamda )
long count = words.stream().filter( w -> w.length() > 12 ).count();
람다를 이용하여 한줄에 작성되었다. 이거 좋다고 이렇게 쓰자고 난리다.
다양한 알고리즘도 미리 제공해주고 있다. 흠 근데 아직 잘 모르겠다. 복잡한거 같다. 패스~
예제 in JAVA 8 with lamda and parallel )
long count = words.parallelStream().filter ( w -> w.length() > 12).count()
어라, 병렬을 한방에 해주네?? 이 정도면 끌리는데? 어려워도 배워볼만하네.
이게 추상화의 장점이구나!! 기능추가의 자유도가 쉽게 높아지는군!
만약 저걸 하둡의 맵 or 리듀스공정에 사용하면 손쉽게 분산병렬과 쓰레드레벨 병렬의 시너지가
날듯합니다.( 여기에 추가적으로 GPU레벨 믹스도 추상화가 높아지면 쉬워지겠네요. )
참고로 c++ 은 저렇게 언어 차원에서 저런식의 병렬을 지원하지 않으며 openMP 나 PPL 같은
외부 라이브러리를 통해 지원합니다.
'소프트웨어 사색 ' 카테고리의 다른 글
정규표현식 (Regex) 정리 (10) | 2015.07.23 |
---|---|
주요 오픈소스 라이센스 (0) | 2015.06.26 |
Actor 패턴 ? ActiveObject 패턴 ? with AKKA (0) | 2015.05.15 |
데브옵스(DevOps) 란 ? (0) | 2015.05.15 |
언어에서 강력함 과 대중성 그리고 스칼라 (0) | 2015.04.27 |
Comments