레이블이 haskell인 게시물을 표시합니다. 모든 게시물 표시
레이블이 haskell인 게시물을 표시합니다. 모든 게시물 표시

2010년 7월 9일 금요일

haskell 로 Win32 HelloWorld 만들어봤다..

haskell 에 Win32 패키지가 어느정도 써먹을수 있는지 궁금해서 google 에서 win32 api hello world 코드를 찾아내서 haskell 로 옮겨봤다. 다시 생각해보면 미친짓이었음.

http://www.codepedia.com/1/Win32APIHelloWorld



펼쳐두기..



2009년 8월 29일 토요일

wxHaskell 로 쪼금 복잡한 코드



간단한 프로토콜 테스터를 짜는중인데 생긴건 챗 클라이언트 혹은 메신저 같이 생긴놈이다.위쪽 넓은 텍스트컨트롤에서는 서버가 보내오는 입력을 눈에 편한 형태로 보여주고 아래쪽 작은 텍스트에딧에 내가 적절히 보낼 패킷을 입력할수있다.

저 패킷 모양을 눈에 익숙하게 보여주기/입력하기 위해서 language-python 패키지 까지 가져다 썼지만 뭐 이건 중요한게 아니고..( 파서를 직접 짜는것 보다 Python 파서를 재활용하는게 더 편했다. )

어쨌건 위처럼 만들고 나니 반복되는 패킷입력을 매번 키보드로 하고 있는게 좀 한심해서 아래쪽에 버튼을 붙여야할 필요성도 생겼다. 그러니까 패킷1, 패킷2 ... 란 버튼들이 줄줄이 붙어있고 그걸 누르면 패킷이 바로 전송 되던가 아니면 입력창에 채워졌으면 편할거란 생각이 들었다.

게다가 이 버튼들은 상황따라 바뀌기 때문에(테스트할 대상에 따라 자주쓰는 패킷이 달라질테니) 코드안에 박기는 뭐하고 바이너리밖에 설정파일로 뽑아야만 했다.(동적으로 바뀐다는건 아니고 그냥 실행시 결정된다는 의미로 적었다. 나중에 동적으로 버튼을 제어할 일도 생기겠지. 그땐 흠 hslua 를 써볼까?)

뭐 필요한 사항은 대강 정리가 됐고..
이제 어떻게 했는지를 적자면

먼저 설정파일은.. 흠 맘에 드는 라이브러리를 못찾아서 (기존 라이브러리는 너무 덩치크거나, 쓰기가 좀 어색하거나..) 그냥 내가 단순히 짜버렸다. haskell 입문서 보면 나오는 간단한 수준으로 짠거라 아주 일부만 여기 적어둔다

펼쳐두기..



이제 wx 쪽 코드를 만져야 하는데.. 흠.. 다소 삽질한 끝에 아래같은 모양의 함수를 만들었다.

펼쳐두기..

패널을 만들어서 패널에 버튼을 적절히 박아주고 패널을 리턴하는 함수. 흠. 저 프라퍼티가 어떻게 구현된건지 함 찾아봐야 겠네. 정말 묘하구먼.



음 이건 지금 코드를 정리해서 위의 내용을 담은 최소 실행 코드. 나중에 이걸 볼때 실행되는 코드가 없으면 난감하겠지.. 소켓쪽이나 등등 많이 덜어냈기 때문에 딱히 어디 쓸수있는 코드는 아니다.

펼쳐두기..












2009년 8월 27일 목요일

wxHaskell 로 처음 만들어본 샘플 프로그램

우선 스샷 박아두고


소스부터 적어두고

펼쳐두기..


몇가지 느낀점들
  1. 레이아웃 잡기 짱난다. 그래도 ghci 로 바로 실행 가능하니 다행. 정말 복잡한 레이아웃 잡으려면 wxWidget 쪽 문서까지 뒤져봐야 할것 같다.
  2. 문서 읽기 어렵다. 어떤 컨트롤이 어떤 프라퍼티를 가졌는지 보려면 먼저 그 컨토롤이 어떤 클래스에 속하는지 보고 그 클래스의 도움말을 찾아보자. 예를들어 위에서 사용자입력을 받을때 쓴 위젯 (entry 로 만든) 은 Commanding 클래스의 멤버라는걸 문서에서 확인하고 엔터를 칠때 뭔가 하고싶으면 command 를 지정하면 되겠구나.. 해서 코딩해본것.
  3. property 라는 것 때문에 퓨어 펑셔널한 라이브러리 라곤 할수가 없을것 같네. OOP 에서 멤버를 바꾸듯이 쉽게 속성을 읽고 쓸수 있다. 뭐 이런 스타일이 더 익숙하지. 퓨어 펑셔널 GUI 가 가능하긴 한가?
  4. this 에 해당하는 뭐 그런걸 못찾아서 좀 어색하다. 예를들어 위 코드에서 i <- entry f [] 부분에서 command 속성을 지정하고 자기 자신을 포인팅 하는 방법을 몰라서(모른다기 보단 그런 방법은 없지).. 일단 i 를 만들고 아래쪽에서 set 으로 속성을 지정해줬다. 코드가 좀 복잡해지면 위젯들을 먼저 왕창 생성해두고 프라퍼티를 줄줄이 수정하는 식으로 짜야 할거 같군?
  5. 위젯에 위젯 올려서 그걸 쓰는 식으로 모듈화를 해야 하는데 예를들어 위 코드로 치면 i 와 b 를 묶어서 inputControls 뭐 이런식으로 묶어야 했는데 못했네. 이건 다음번에.




2009년 8월 26일 수요일

win32, haskell 에서 gui 는 wxHaskell 가 시작하기 좋군.

간단한 프로토콜 테스트 클라이언트를 haskell 로 짜보려고 준비중이다.
원래 콘솔로 만들까 했는데 트래픽이 좀 되니 콘솔로는 부족해서 GUI 를 붙여볼 생각.

처음에는 Gtk2Hs 를 고려해봤는데 이게 windows 에서는 설치가 매우 곤란했다. 지금 쓰는게 haskell platform 인데 이게 설치경로에 공백이 들어가있어서 gtk2hs 의 configure 가 에러를 뱉는다. haskell platform 만든애들이 이문제 때문에 설치경로를 바꿨다가 Gtk2Hs 쪽에서 해결하라고 다시 원복하는 바람에 이게 허공에 뜬 이슈가 됐다. Gtk2Hs 쪽 에도 이슈로 올라와있지만 조용하고...

뭐 저문제 말고도 여러문제가 있길래 설치하다 결국 꽥

반면에 wx haskell 쪽은 최신 버전에 맞는 바이너리 설치본을 제공해서(Gtk2Hs 쪽 바이너리 설치본은 ghc 구버전용) 설치가 깔끔하더라.

아.. qt 쪽도 haskell 바인딩 라이브러리가 있는데 그쪽은 시도도 안해봤다.


펑셔널 GUI 라니 어떻게 짜야 하는지 상상도 안되네.
어쨌건 wx window 를 배우기 위해서는 아래 링크들을 띄워두고 놀아보자.

http://haskell.org/haskellwiki/WxHaskell
http://en.wikibooks.org/wiki/Haskell/GUI
http://wxhaskell.sourceforge.net/doc/

추가.
으흠.. FAQ 에 의하면 멀티쓰레드지원이 아직 안된다는 말이 있네.. 헐..

2009년 8월 21일 금요일

haskell 확장 RecordWildCards

메뉴얼 참고
NamedFieldPuns 확장하고 같이 쓰면 타이핑 줄이는데 도움이 많이 되겠네   

쌩기초 문법만 알고 있는 상태에서 haskell 코드 구경하다 이런 문법을 만나면 정말 난감하다. lisp 이면 매크로를 따라갈수라도 있지. haskell 의 경우 좀 덩치큰 소스는 확장을 여러개 해서 LANGUAGE 프라그마가 여러개 나오는데 해당 소스의 신기한 문법이 도대체 어디서 나온건지 알수가 없다...

뭐 천천히 구경을 계속해보자.

{-# LANGUAGE RecordWildCards #-}

-- 많은 필드를 가진 레코드가 있을때
data C = C {
a :: Int,
b :: Int,
c :: Int,
d :: Int
} deriving (Show)


-- 원래대로라면 미칠듯한 타이핑을 해야한다.
f C{a=a, b=b, c=c, d=d} = a+b+c+d

-- .. 으로 모든 필드를 읽어올수있다.
g C{..} = a+b+c+d

-- 일부만 패턴을 주는것도 가능
h C{a=1,..} = b+c+d

-- 헐 이런짓도 가능.
i = C {a=1,..}
where b=2
c=3
d=4


haskell 확장 NamedFieldPuns ( record puns 라고 불리는듯 )

메뉴얼 참고.
이거 알아두면 편하겠군?


{-
# LANGUAGE NamedFieldPuns #-}

-- 이런 레코드 타입이 있다고 치자. 보통 함수에서는 모든 필드를 참조할
-- 필요가 없으니 패턴매칭으로 필요한 필드값만을 꺼내서 쓰는 식의 코딩이
-- 된다.
data C = C {
a :: Int,
b :: Int,
c :: Int
} deriving (Show)

-- 레코드 타입의 패턴매칭 기본 문법은 아래와 같다.
-- TypeName{fieldName=varName, ..}
f C{a=foo,b=bar} = (foo,bar)


-- 하지만 타이핑이 귀찮으니 보통 이런식으로 적을때 필드이름과
-- 변수이름을 같은 이름을 쓰는게 일반적.
g C{a=a, b=b} = (a,b)


-- NamedFieldPuns 확장을 쓴다면 필드이름과 변수이름이 같을경우 짧게
-- 타이핑하는게 가능해진다. 이런 확장을 record punning 이라고 칭하는
-- 모양이다.
h C{a,b} = (a,b)


-- puns 는 다른 패턴과 섞어쓰는것도 가능
i C{a, b=1} = 1
i C{a, b=2} = 2
i C{c} = c


-- 패턴매칭이 적용되는 다른부분(let등)에도 적용가능
j = let a = 1
b = 2
c = 3
in C {a,b,c}

2009년 5월 29일 금요일

haskell, happstack 에서 Text.Html 통해서 한글 출력

  마이너 언어를 배울때 가장 골때리는게 한글문제다. 역시나 haskell 도
  마찬가지라 한글이 엮이면 좀 난감해 지는데 뭐 포터블한 한글파일명
  처리는 바라지도 않지만 그래도 리눅스상에서 한글을 뿌리는건
  가능해야겠지. 어쨌거나 기본 모듈인 Html.Text 로 간단히 한글을
  포함하는 html 을 만들어 보고 이놈을 Happstack 을 통해서 뿌려봤다.

  먼저 Text.Html 은 html 을 뽑아낼 함수덩어리들을 유지하다가
  renderHtml 등으로 실행을 하면 String 타입의 html 을 돌려주는 놈이라고
  보면 된다. haskell 의 String 타입은 아주 엿같다고 생각하기 때문에
  이런 동작이 그다지 맘에 들진 않지만.. 뭐 어쨌거나 String 으로만
  뽑아주게 되어있다.

  Happstack 은.. 뭐 결국 응답으로 쓸수있는 타입이 ToMessage 란
  타입클래스의 인스턴스여야 하는데 결론적으로 toMessage 라는 함수에
  의해서 ByteString 으로 변환후 이걸 브라우저에 뿌려준다고 보면
  되겠다.

  마침 Html 이 ToMessage 의 인스턴스로 잡혀있어서 따로 렌더를 부르지
  않고 바로 Html 을 리턴해주면 알아서 적절히 풀어주게 되어있는데
  문제는! 이 인스턴스 구현 소스를 보면 알지만 renderHtml 한 결과물인
  String 을 Data.ByteString.Lazy.Char8.pack 을 통해서 바이트스트링으로
  바꾼다는거다. Char8 타입이 어떻게 돌지는 모르겠다만 유니코드를
  담고있는데 8 이란꼬릴 달고있는 타입을 적용했다는거 자체가 뭔가
  안좋다는게 느껴진다.

import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as L

instance ToMessage Html where
toContentType _ = B.pack "text/html"
toMessage = L.pack . renderHtml

  마침 얼마전에 봐둔 utf8-string 이란 패키지가 있었고 그쪽 문서를
  둘러보니 Data.ByteString.Lazy.UTF8 이란 모듈이 보였다.. 흠. 이런식의
  모듈간의 호환성을 이용한 라이브러리 구성은 정말 익숙해지질
  않는군.. 어쨌거나 저놈을 이용해서 바이트스트링으로 바꿔주니 한글이 잘
  보이더라.

import Happstack.Server
import Text.Html
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.UTF8 as U

main = simpleHTTP conf handler
conf = Conf 8080 Nothing
handler = return f

hello = header << thetitle << "안녕"
+++ body << "세상"

f = U.fromString $ renderHtml hello

instance ToMessage U.ByteString where
toContentType _ = B.pack "text/html"
toMessage = id

  음.. 사실 ToMessage Html 인스턴스를 유니코드먹인걸로 덮어쓰고
  싶었는데 방법을 잘 모르겠네. 기존 인스턴스를 무시하고 새인스턴스를
  정의한다거나 하는건 안되나? newtype 으로 새 타입을 만들어주는 삽질을
  해줘야 하는건가? import 시 적절히 저놈만 제외해줄수는 있나? 흠.






 

2009년 5월 7일 목요일

haskell 로 웹개발을 진행해본이의 소감글 링크

Is Haskell a Good Choice for Web Applications?
reddit
reddit
haskell-cafe

haskell 로 직접 굴러본 이의 글이니 그냥 다른글들보다 믿음이 가는군.
원문 댓글중에 happstack 에 대한 언급이 있는데 그게 특히 볼만할듯.

2009년 4월 23일 목요일

haskell 잠깐 둘러보면서 느낀것들 횡설수설

haskell 이 실용적인 언어는 아니라고 생각되서 앞으로 더 haskell 문서를 보게될지 모르겠네. 어쨌건 haskell 을 배우면서(배웠다기 보다는 정말 구경한거.. 그냥 지하철에서 문서좀 읽다 자다가.. 간단히 샘플몇개 코딩해본게 전부지) 내 코딩스타일을 바꿔야 할점들을 몇개 더 알게됐는데 정리해두자.

아 그전에 망할 모나드 트랜스포머.. 모나드 스택 은 킹왕짱좋은 개념이란건 알겠는데 결국 이산을 못넘은게 좀 아쉽긴 하다. 뭐 대강 왜 이친구들이 모나드를 스택식으로 쌓아올렸는지 뭐 그 필요성? 그걸로 얻은 것들? 뭐 그런것들에 대해서 냄새는 맡았지만.. 뭐 그걸로 얻는게 많다는것도 알게 됐지만 내눈엔 가까운길 놔두고 멀리 돌아가는 길로밖에 안보인다. 코딩을 이렇게 까지 복잡하게 해야 하는것에 납득할수가 없었다.

뭐 순수함수형 언어라는게 그렇더라. 순수함을 지키기 위해서 희생이 너무큰데 글쎄.. 그렇게 까지 지킬 필요가 있을까. 어차피 컴퓨터 라는 기계 자체가 펑셔널 하질 않은것을.


어쨌건 몇가지 적어둔다.
  • 먼저 pure functional 이란 말부터.. 가장 중요한것은 값이 일단 정해지면 절대 변하지 않는다는게 기본 개념이다. 물론 이게 되면 여러가지로 장점이 많지. 보통 함수형언어 책들 앞대가리들 읽어보면 이런 내용이 줄줄이 나온다. 그런데 내 결론은 그거 죄다 헛소리. 꿈꾸는 소리. 그러고 보면 haskell 이 여기까지 발전한게.. 정말 haskell 커뮤니티 애들은 천재들의 집단인거다.
  • 모나드.. 음 이게 정말 뭐랄까 대단하다. 모나드 자체는 정말 별거 아닌데 응용이 무지막지하게 나온다. 처음 이개념을 도입한놈은 천재중의 천재라고 할수 있겠네.. 어쨌건 실체는 뭐랄까.. 만들기 졸라 불편하면서 동시에 오사용을 막을수있는 매크로 랄까. 현재 언어스펙으로 나타내기 어려운 개념을 표현한다는 점에선 lisp macro 와 유사하지만.. lisp macro 가 만들고 쓰는게 상당히 자유로운것에 비해 monad 는 아주 번거롭게 틀에 같힌 형태?(좀더 좋게 표현하면 그 monad 가 나타내는 world 에 안전하게 격리된 상태 낄낄) 대신에 macro 를 많이 쓰는 경우 스파게티가 나오지만 monad 는 계층형태로 이쁘게 쌓아올리는 식의 코딩이 가능하다.( 모나드 트랜스포머.. ) 뭐 이렇게만 쓰면 monad 개념이 아주 좋은게 맞는데.. 뭐 자세히 지금 내 기분을 적기가 어렵지만 어쨌건 monad 는 코딩이 아주 번거롭다.. 이건 내가 C 식의 사고를 하기 때문인건데.. 뭐 어쨌건 monad 는 존나 좋은 개념. 하지만 나한텐(대부분의 다른 개발자들도 마찬가지라고 생각되는데) 아주 불편한 개념.

헐.. 글을 막쓰다 보니 주제를 벗어났네. 요점만 적자. 앞으로 내가 코딩하면서 몇가지 신경써줄것들이다.
  • pure code 와 impure code 의 분리. 이건 사실 굳이 함수형 언어 개발자가 아니더라도 몸으로 알고있는 사실. 하지만 haskell 의 경우 언어가 이런면을 강요하다 보니 좀더 분리에 신경을 쓰게 됐는데 이런식으로 철저히 분리를 하고 나니 코드가 좀더 유연해지더라. 이건 사실 모듈화를 잘하라는 진리와 상통하는 말이다.
  • typeclass 의 사용.  이건 결국 템플릿 메타 프로그래밍으로 이어지겠지. 그리고 데이타모델링에 OOP 를 피하는 좋은 수단이기도 하고. 이런류의 내용은 C++ 쪽 문서들에도 몇번 강조되고있는 글인데 haskell 로 좀 코딩하다 보니 감이 잡히더라. 단 글로 나타낼정도로 명확히 정리하지 못해서 좀 아쉽다. 뭐 내가 하는게 다 그렇지.
  • 위험한 코드는 아예 빌드가 안되도록. 이것도 당연히 이미 여러 C++ 문서에서 다루고 있는 것이지만 다시한번 느낀점이다. 컴파일러가 잡아주는게 가능한 문제라면 무조건 컴파일러가 잡아줘야 한다. 또는 컴파일러가 잡아주도록 만들어야 한다. 그냥 읽고 지나갔던 static assert 나.. 여러 템플릿 기법을 다시 둘러봐야 겠다.  난 static assert 를 잡느니 main 앞에 assert 를 모아두는걸 좋아하는 편인데.. 앞으론 좀 적극적으로 써봐야 겠다. 이미 boost 의 경우 유명해져서 이것저것 써도 태클 들어올일은 적을테고 말이지. 코드를 짤때 위험하게 쓰일 경우를 대비해서 주석한줄 달랑 적지 말고 최대한의 방어를 하자. 특히 C++ 클래스는 컴파일러가 말없이 만드는 코드들이 많고.. 또 타입캐스팅이 말없이 일어나는 경우가 많으니 주의 또 주의.
  • 최소한의 함수들을 만들어서 조립. haskell 의 compose 는 정말 쇼크였다. 일단 문법이 편히 받쳐주니 여러가지를 composing 해서, 또는 compose 를 염두에 두고 만들어봤는데 정말 그리 좋을수가 없더라. 아직 C++ 이 이런식으로 사용하기는 적절하지 않은데 뭐 다른 편법을 쓰더라도 이놈은 좀더 공부해둘 필요가 있다. 흠 그런데 이런식으로 코딩하려면 제네릭한 함수가 있어야 하고.. 결국 템플릿 메타 프로그래밍(evil)으로 빠진다.

그외.. 꼭 haskell 이라서 라기 보단.. haskell 쪽에 몇가지 굉장히 매력적인 라이브러리들(QuickCheck, STM, Parsec 등등)이 있는데 내방식대로 써먹을 방법을 찾아봐야겠다. 또 FRP 란놈도 좀 흥미가 생기던데 아직 구경도 안해봤다. 이건 좀 아쉽군..

아.. 그리고 순수함수형 데이타구조에 대한 글들도 좋은게 많던데 이건 좀 읽어봐야겠더라. 이친구들은 이게 성능이 나쁘지 않다고 말을 하던데 흠.. 사실 믿어지질 않네.

어.. 하나 더. haskell 의 중요한 특성중에 lazy 가 있는데 흠. 글쎄 난 이놈에겐 별 매력을 못느겼다. lazy 특성때문에 얻은 장점이 아주 많다는걸 알겠는데 ( 무한 자료구조 같은경우는 정말 깨더라. 여기에 리커시브까지 끼면 후럴... ) 이 코드가 실제로 어떻게 돌아가는지 상상이 잘 안되더라. 이것도 뭐 숙련도 문제이긴 헌데 나한테는 넘을수없는 벽이었다. strict 가 기반이고 lazy 는 선택적으로 쉽게 지원해주면 좋았을텐데.. 참고로 clojure 가 strict 가 기본에 lazy-cons 라는 적절한 놈을 지원하더라. 우왕ㅋ굳ㅋ
(사실 언어가 돌아가는 모양을 알아야 되겠다는게 선언적 언어인 haskell 에는 좀 안어울릴수도 있는데 알고싶은걸 어쩌랴? 적어도 메모리가 얼마나 쌓이는지는 알아야지)

추가로.. 맘에 안들던점. 망할 언어확장. haskell 98 이 오래된 스펙이라 몇가지 추가기능들을 확장이란식으로 제공하던데 이건뭐.. haskell 의 발전을 옆에서 지켜본 사람이 아니면 그런 확장이 있는것도 모를테고.. 아니 사실 이건 haskell 의 문서부족에 대한 불평이네. haskell 문서들은 그냥 레퍼런스거나 아니면 거창한 내용을 담고있는 논문레벨의 문서(확장가능한 익셉션.. 이건뭐 정말 깨더군. 글쎄 다른언어같았다면 그냥 언어차원에서 구현하고 이리쓰셈. 하거나 확장가능한 언어라면 라이브러리단에서 붙이고 친절한 튜터리얼을 줬을텐데 haskell 은 이게 부족해서 문서를 찾다보면 논문까지 도달하게 되더라. 꽥 아니 뭐 이게 더 나은 모양이긴 하지만...)..

윗문단 다시 정리하면 튜터리얼의 부재가 상당히 짜증났다. 몇몇 문서들은 이게 프로그래머(haskell 구현자가 아닌 haskell 유저) 보라고 쓴건지 수학자 보라고 쓴건지.. 용어는 다른 언어와 미묘하게 다르고 뭐 생소한 학문에서 따온 용어를 언어에 붙여넣은것도 있고 어쨌건 haskell 은 그들만의 언어라는 느낌이 강하다.

엇 그리고 보니 haskell 의 장점중 하나가 병렬성인데 이쪽은 전혀 안봤네. 이건 나중에 다시 한번 둘러보자..


음. currying 에 대해서도. 이것도 킹왕짱. 아주 끌리는 언어적 기능. 전에 ocaml 구경할때는 그냥 그런갑다 했는데 이번에 이게 얼마나 좋은지 느꼈다. 뭐 lisp 애들은 매크로로 만들어 쓰는거 같던데 헐. 어쨌거나 함수를 받아서 함수를 내놓는다는 그야말로 고차원적 코딩이 자연스럽게 이루어지는 기반이라고도 할수있는데 아쉽게도 현재 C++ 에서는 쓰기가 좀 애매하다. boost::bind 를 써서 흉내가 가능하긴 한데... 흠. 다음 표준에 람다가 어느정도까지 들어가는지 좀 확인해보고 고민해보자.













2009년 4월 8일 수요일

haskell 에러 처리의 복잡함

http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors

http://thread.gmane.org/gmane.comp.lang.haskell.libraries/6382


haskell 공부하려면 읽어둘만한 글이군. 대강 심심풀이로 보는 수준이라 저기에 제시한 방법중 내가 아는건 4개밖에 없다.

코드규모가 어느정도 수준이 되면 상당량이 에러/예외처리/땜질 등이 될수밖에 없는데 haskell 은 이런 면에서 너무나 답답하다. 물론 haskell 의 이런 에러 구분이 논리적인게 맞긴 하지만 인간이란게 애초에 논리적이지 못하지.

뭐 타입위주로 코딩하는 버릇이 들면 달라질지도 모르겠지만 지금 내게는 너무 어색하네.


PS.
extensible exception 이라면 내 몇줄 안되는 짧은 코드를 ghc 버전이 올라가면서 수정(Old 라이브러리를 import 하도록 수정해야 했다)하도록 만든놈인데  위 토론에 언급이 되어있네. 에러처리에 대해서 뭔가 개선이 있었던것 같은데 후에 읽어보자.

2009년 3월 27일 금요일

ghc 소켓제한

http://hackage.haskell.org/trac/ghc/ticket/635

소켓 스트레스 테스트를 짜기위해서 먼저 그냥 소켓만 열어두고 아무일 안하는놈을 만들어봤다. haskell 쓰레드는 erlang 처럼 가벼운놈이라 몇개를 열건 별무리없이 소화하겠지.. 했는데 소켓 천개정도 만든후엔 뻗어버리더라. ulimit 제한은 먼저 풀어둔 상태고..

적절히 구글링 해보니 ghc 가 내부적으로 소켓을 다룰때 select 를 쓰기때문에 생기는 문제라고 하는데.. 뭐 수정될거라고는 하지만 기분이 좀 드럽군. ghc 면 역사가 몇년인데 아직도 이런 문제가 있는건지.

역시나 내가 하는 일들에 쓰기는 어렵구만.


2009년 3월 9일 월요일

win32 cabal 바이너리 다운로드 페이지

http://www.haskell.org/cabal/download.html

이게 다시 찾으려니 안보여서 좀 헤맸네.
다시 찾으려면 또 헤멜거 같아 적어둔다.

여러 마이너(?) 언어들처럼 ghc 도 리눅스쪽이 메인플래폼이라 윈도에서 쓰려면 졸라 짜증나는데 현재 ghc 셋업본도 cabal update 후 upgrade 하면 빌드중에 에러가 뜬다. 혹시나 해서 집에 하드정리 하면서 지웠던 ghc 를 새로 깔고 cabal 새버전을 써보니 아예 upgrade 명령을 막아놨네.

시험삼아 cabal install happstack 을 해봤는데.. 헐 이놈이 happy 에 의존성이 걸린걸 자동으로 못받아 주는모양.. happy 를 직접 설치할려고 했더니 이번엔 perl 이 없다고하네. 윈도에선 게임만 해야겠다.

2009년 3월 3일 화요일

haskell 로 프로젝트 오일러의 25번 문제를 풀어봤다

http://www.haskell.org/haskellwiki/Memoization 읽어보자.
오일러 포럼에는 수학적으로 푼 넘들도 많은데 헐..
어릴때 공부 안한게 후회스러울 따름.
http://www.haskell.org/haskellwiki/Euler_problems/21_to_30#Problem_25
도 참고해보자.. 그런데 읽기 어렵네. 어쨌건 돌려보니 내거하곤 성능차이가..
한글위키피디아에 이런 페이지도 있다.


import
Data.List(findIndex)

-- 간단한 구현. 이건 속도때문에 꽝. 코드가 트리형태로 전개되기 때문에
-- 매우 느리다.
fibBad 1 = 1
fibBad 2 = 1
fibBad n = fib (n-1) + fib (n-2)


-- 헐 쫌더 나은 버전일랑가.
-- 함수형 언어라면 간지나게 memoize 등을 써서 푸는게 맞을거 같은데
-- 간단히 Data.Map 하나 두고 캐시처럼 써먹는 모듈을 짜보려고 했으나
-- 실패. 이거뭐.. 어떻게 시작해야 할지도 모르겠더라. 일단 문제는 풀어야
-- 겠으니 익숙한 식대로 루프돌렸다.
fib 1 = 1
fib 2 = 1
fib n = f 3 1 1 2
where f step older old cur
| step == n = cur
| otherwise = let newstep = step+1
newolder = old
newold = cur
newcur = newolder+newold
in f newstep newolder newold newcur

-- fib 함수로 리스트 생성
fibs = map fib [1..]

-- 자릿수
digits :: (Num a) => a -> Int
digits = length . show

-- 풀이. 리스트는 0 base 이고 위 fib 는 1 base 이므로 1 만큼 보정을 했다.
solve = (+1) `fmap` findIndex ((==1000) . digits) fibs

-- 우왕국
-- 현재 내 PC 에서는 대략 2 초정도에 끝난다.
main = print solve

2009년 2월 27일 금요일

haskell 동영상 강의

Video Lectures
Lectures (in English) by Jürgen Giesl. About 30 hours in total, and great for learning Haskell. The lectures are 2005-SS-FP.V01 through 2005-SS-FP.V26. Videos 2005-SS-FP.U01 through 2005-SS-FP.U11 are exercise answer sessions, so you probably don't want those.

우왕국. http://www.haskell.org/haskellwiki/Tutorials 에서 찾은 링크인데 잠깐 들어보니 좋네. 딴나라 말이라 좀 난감하긴 한데 독일사람이 영어하는거라 좀 들을만 하다...(발음이야 좀 이상하지만 느리게 말해주는 편. 뭐 강의 뒤쪽가면 말이 빨라지거나 하진 않겠지....)

2009년 2월 24일 화요일

haskell 로 간단한 소켓 서버와 클라이언트 제작 두번째

이전글 에서는 코드가 전체적으로 Socket 기반으로 돌아가는데 뭐랄까.. 이게 그다지 좋은 방법이 아닌가보다. haskell 의 경우 입출력이 Handle 을 통해서 이루어지게 디자인 되어있어서 Socket 을 바로 입출력에 쓰기엔 제공되는 api 들이 좀 난감한 면이 있다.

그래서 이전 코드에서 세션핸들러 함수들이 Socket 을 받던것을 Handle 을 받도록 수정해봤다. 그리고 핸들(소켓) 을 닫는 책임을 세션핸들러 쪽으로 옮겨버렸다... 세션함수 작성시 클로즈를 잊지말고 해야 하는 부담이 있긴 하지만 이게 좀더 유연할거 같다.


이건 서버쪽 소스

펼쳐두기..

이건 클라이언트쪽 소스

펼쳐두기..





haskell 로 간단한 소켓 서버와 클라이언트 제작

이건 서버 소스. serveTcp 가 핵심. 이 함수에 포트번호와 소켓핸들러 함수를 넘기면 된다.

펼쳐두기..


이건 클라이언트 소스

펼쳐두기..


으음... 이건 패킷이 너무 단순해서 별 의미는 없지만 위에 withTcp 나 serveTcp 는 자주 쓰일 함수들이라 적어둔다. 다음에는 현재 Socket 기반인것을 Handle 기반으로바꾸고.. 바이너리패킷을 쏘는걸 한번 만들어보고.. 그담엔 서로 주고받는걸 만들어보자...



2009년 2월 17일 화요일

haskell 로 프로젝트 오일러의 22번 문제를 풀어봤다

-- http://projecteuler.net/index.php?section=problems&id=22

import Data.List(sort)
import Data.Char(ord)

-- 으험.. 스플릿 함수가 안보이네. 직접 만들어봤는데 좀 추해보인다.
split :: Char -> String -> [String]
split c s = split' [] s
where split' acc [] = acc
split' acc s = let (tok, remains) = break (==c) s
in split' (tok:acc) (safeTail remains)
safeTail [] = []
safeTail x = tail x

-- 문자열들을 받아서 , 로 스플릿 하고 앞뒤에서 한글자씩 잘라냈다.
-- 따옴표 제거
names s = map (tail . init) $ split ',' s

nth x = (ord x) - (ord 'A') + 1 -- 'A' 에서 몇번째 문자냐
scoreName = sum . map nth -- 이름의 점수
scoreIndexedName (name,index) = (scoreName name) * index -- 점수에 인덱스 곱

solve input =
let splitted = names input -- 쪼개고
sorted = sort splitted -- 정렬하고
indexed = zip sorted [1..] -- 인덱스붙여서
scores = map scoreIndexedName indexed -- 점수내고
in sum scores --

main = do
input <- readFile "/tmp/h/names.txt"
print $ solve input

2009년 2월 11일 수요일

haskell-mode 에서 ^J 가 찍혀대는 문제 해결

http://www.nabble.com/problem-with-echo-prompting-in-ghci-(visible-in-emacs)-td20451779.html

ghc 6.10.1 로 올리고 haskell-mode 도 올리고 보니 이런 문제가 생기네.
적당히 구글링해서 해결.


혹시나 내용백업해둔다.

펼쳐두기..



ghc 6.10 이 되면서 생긴 Exception 변화

흠.
먼저 6.10 을 깐 배경.
우분투는 아직 6.8 을 패키징 하고 있는데 cabal 하고 같이 쓰려니 좀 문제가 있더라.
그래서 apt 에서는 지워버리고  ghc 6.10.1 바이너리 배포본을 받아 직접 설치해줬다.

그러고 나니 6.8 에서 쓰던 코드들이 에러를 뱉어내네..
조금 검색해보니 이런글이 보였다.
http://groups.google.com/group/fa.haskell/browse_thread/thread/8c6352ed6767952d

결론.
OldException 을 임포트 하거나
타입지정을 하자??
음 타입지정 말고 좀 깔끔한 방법은 없을까? 보통 람다로 핸들러 짜는데 말이지.

http://www.haskell.org/ghc/docs/6.10.1/html/users_guide/release-6-10-1.html
는 읽어봐야 할듯?



2009년 2월 4일 수요일

haskell 에서 랜덤값 사용하기

랜덤하나 부르는것도 힘드네. haskell 의 System.Random 문서를 보고
정리해봤다.

먼저 모든 RNG 는 RandomGen 이란 타입클래스에 속해있는
모냥이군. 음.. RandomGen 의 인스턴스라는 소리를 그 타입클래스에
속해있다.. 라고 표현하는게 맞는 건지 잘 모르겠지만.

class RandomGen g where
  next     :: g -> (Int, g)
  split    :: g -> (g,g)
  genRange :: g -> (Int,Int)

next 는 뭐 간단한 모양이군. 랜덤값 하나를 뽑아주고 이때문에 바뀐 새
상태를 같이 리턴해준다. 뭐 여기까진 이해가 되는데.

split 은 g 를 쪼개주는데.. 문서상에야 설명이 있지만 이해가 잘 안가네.

genRange 는 그냥 그 g 가 뽑아내는 랜덤값의 범위다. 내공이 부족하여
처음에 이 함수 모양만 가지곤 뭐하는지 추측이 안되더군. 단순히 getter
였을줄이야.


위는 타입클래스라.. 실제로 뭔가 돌아가는놈은 위 타입클래스의 인스턴스
일테고 haskell 은 표준으로 StdGen 이란놈을 가지고 있구나.

*Main> :info StdGen
data StdGen = System.Random.StdGen GHC.Int.Int32 GHC.Int.Int32
      -- Defined in System.Random
instance Read StdGen -- Defined in System.Random
instance Show StdGen -- Defined in System.Random
instance RandomGen StdGen -- Defined in System.Random

StdGen 은 밸류 컨트스럭터가 노출이 안되어있고 mkStdGen 이란 함수를
통해서 값을 만들수 있다. 이 함수가 받는 인자는 seed 로 쓰이는
놈이겠지.

자.. 이제 직접 랜덤값을 뽑아낼정도로 함수들을 알게됐으니 일단 불러보자.

*Main> next (mkStdGen 0)
(2147482884,40014 40692)
*Main> genRange (mkStdGen 0)
(0,2147483562)

우왕ㅋ굳ㅋ mkStdGen 0 으로 제네레이터를 만들고 next 로 랜덤값과 새
제네레이터를 뽑아냈다. 여러값을 불러야 하면 새 상태를 적절히 체이닝
해야겠지. 랜덤을 뽑는 행위에 사이드이펙트가 없다는게.. 뭐랄까 응용할
꺼리가 많겠군.


음 그런데 전역상태에 의존해서 랜덤을 생각없이 쓰다가 이렇게 매번 상태를
관리하는 랜덤을 쓰는건 정말 괴롭겠지. 다행히도 haskell 에 IO 모나드에
속한(전역인) StdGen 이 있다. 한마디로 말해 다른 언어에서 랜덤 쓰던것과
동일하게 쓸수 있다. 굳이 새상태를 들고다니는 짓을 안해도 된단말이지.

getStdRandom :: (StdGen -> (a, StdGen)) -> IO a
getStdGen    :: IO StdGen
setStdGen    :: StdGen -> IO ()
newStdGen    :: IO StdGen

getStdGen 와 setStdGen 은 간단한 엑세서 함수다.

무식하게 쓰려면 꺼내서 next 로 새값과 새상태 만들고 새 상태를
setStdGen 으로 박아넣는 식으로 돌아가겠지. 이게 아주 뻔한 작업이 될테니
getStdRandom 함수를 제공해준다. 타입만 봐도 어느정도 돌아가는 모양이
예측이 가능하네.. 하지만 실제 이 소스를 보면 IORef 등 더 공부할게
튀어나온다. 더 깊이는 안보고 넘어가야지..

아 실제로 쓰는건 요리 쓰면 된다.

*Main> getStdRandom next
501819957
*Main> getStdRandom next
557655835
*Main> getStdRandom next
1527018794
*Main> getStdRandom next
1881200278

매번 부를때마다 새로운 값이 튀어나오는게 확인된다.


음 그런데 이렇게 next 를 통해서 값을 가져오면 내가 원하는 모양으로 다시
가공을 해야 하는데(적정 범위안으로 구겨넣는다던지, 이 값을 인덱스로
해서 리스트로부터 랜덤하게 엘리먼트를 뽑는다던지..) 상당히
불편하지... 뭐 불편하다고는 하지만 이미 이렇게 잘 써왔지만.

어쨌거나 haskell 은 위와 같은 가공을 개발자한테 알아서 하라고 그냥 둔게
아니고 적절한 유틸리티 함수들을 제공을 하고 이 함수들을 Random 이란
클래스로 묶어뒀다. 사실 이제까지 내용은 그냥 haskell 은 이러하다.. 란
식이라 머리쓸일이 없었는데 이 Random 클래스는 음.. 좀 어렵군.

class Random a where
  randomR  :: RandomGen g => (a,a) -> g -> (a,g)
  random   :: RandomGen g => g -> (a,g)
  randomRs :: RandomGen g => (a,a) -> g -> [a]
  randoms  :: RandomGen g => g -> [a]
  randomIO :: IO a

먼저 randomR 은 모양만 봐도 next 한 값을 주어진 범위 안으로 구겨넣는
놈이라는걸 알수있다.

*Main> getStdRandom (randomR (0,10))
10
*Main> getStdRandom (randomR (0,10))
9
*Main> getStdRandom (randomR (0,10))
5
*Main> getStdRandom (randomR (0,10))
8

haskell 의 특징인 currying 때문에 위 예제에서 쓰인 randomR (0,10) 의
타입은 정확히 next 와 일치하고 따라서 getStdRandom 의 인자로 사용이
가능하다.. 이런식의 currying 사용은 빨리 익숙해져야 할텐데.

random 은 randomR 의 범위에 리턴받을 타입의 유효범위를
지정해준것. 위에서 봤다시피 그냥 next 의 범위는 genRange 를 불러보면
알겠지만 리턴받을(생성할) 타입의 값과는 무관하다. 따라서 이걸 적절히
바꿔줄 놈이 필요한데 이 함수가 그짓을 해준다.

*Main> getStdRandom random
-864292929

randoms 는 후럴... 희한한 놈이네. 새상태는 리턴해주지 않고 무한히
랜덤값을 찍어내주는 놈이다. 일단 randoms 부르면 함수 안쪽에서 새값을
유지하면서 루프(리커젼)을 돌테니 굳이 새상태를 리턴받지
않는것이겠지.. 음.. 이 무한이란 개념도 내가 지금껏 다뤄오던 언어들에선
접하기 힘든거라 randoms 타입만 봐서는 뭐하는놈인지 정말 애매했다. 만약
내가 이런류의 함수를 만든다면 몇개의 엘리먼트를 뽑을지 인자로 받을텐데
haskell 에서는 그냥 무한리스트를 주고 필요한쪽에서 필요한만큼 가져다
쓰는 방식히 선호되는듯 하다( lazy 하니까 ) 이런 스타일이 어여 손에
익어야 할텐데. (좀더 자세히 말해서 무한리스트를 준다는 표현은
잘못된거지. lazy 하다는 특성때문에 randoms 함수가 불리는 순간에 값이
만들어 지는게 아니니까. 무한리스트를 준다 라는 표현보다는 나중에
필요할때 값을 만들어낼 방법을 미리 정의만 해둔다.. 정도가 맞겠지.)


*Main> take 5 $ (randoms (mkStdGen 0)) :: [Int]
[2092838931,-2143208520,2034827062,-1587933427,-1272503422]

randoms 의 타입을 보면 알겠지만 getStdRandom 하고는 잘 안섞인다(이글을
쓰는 현재 같이 섞어 부르는 방법을 모르겠다. 아마 없을거 같은데)

randomRIO 는 흠. getStdRandom 을 내포한 놈인거 같군. 위 적은 코드중에
getStdRandom 하고 randomR 을 쓴게 있었는데 randomRIO 를 쓰면 한방이구나

*Main> randomRIO (1,10)
6
*Main> randomRIO (1,10)
2
*Main> randomRIO (1,10)
1

randomIO 는 getStdRandom 하고 random 을 섞은놈이구먼.
                                           
*Main> randomIO
-795885308


마지막으로..  Random 이 타입클래스로 빠져있는게 아주 오묘하구나. 내가
랜덤생성을 원하는 타입에 따라 다른 동작을 해준다는 건데 음... 뭔가
느껴지긴 하는데 글로적기는 힘들군. 타입클래스 사용도 좀더 구경하다 보면
감 잡겠지.