by shigemk2

当面は技術的なことしか書かない

EmacsでHaskell環境を作りたい

五番茶煎じ(当社調べ)くらいであろうやつ。

d.hatena.ne.jp

sites.google.com

もろもろ参考に、自分のHaskell用elispを貼っつけてみる。

(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
(add-hook 'haskell-mode-hook 'font-lock-mode)
(add-hook 'haskell-mode-hook 'imenu-add-menubar-index)

(custom-set-variables
 '(haskell-indent-after-keywords (quote (("where" 4 0) ("of" 4) ("do" 4) ("mdo" 4) ("rec" 4) ("in" 4 0) ("{" 4) "if" "then" "else" "let")))
 '(haskell-indent-offset 4)
 '(haskell-indent-spaces 4))

;; http://d.hatena.ne.jp/kitokitoki/20111217/p1
;; ghc-mod
;; cabal でインストールしたライブラリのコマンドが格納されている bin ディレクトリへのパスを exec-path に追加する
(add-to-list 'exec-path (concat (getenv "HOME") "/.cabal/bin"))

;; ghc-flymake.el などがあるディレクトリ ghc-mod を ~/.emacs.d 以下で管理することにした
(add-to-list 'load-path "~/.emacs.d/ghc-mod")

(autoload 'ghc-init "ghc" nil t)
(autoload 'ghc-debug "ghc" nil t)
(add-hook 'haskell-mode-hook (lambda () (ghc-init)))

;; ;; https://github.com/m2ym/auto-complete
(ac-define-source ghc-mod
  '((depends ghc)
    (candidates . (ghc-select-completion-symbol))
    (symbol . "s")
    (cache)))

(defun my-ac-haskell-mode ()
  (setq ac-sources '(ac-source-words-in-same-mode-buffers ac-source-dictionary ac-source-ghc-mod)))
(add-hook 'haskell-mode-hook 'my-ac-haskell-mode)

(defun my-haskell-ac-init ()
  (when (member (file-name-extension buffer-file-name) '("hs" "lhs"))
    (auto-complete-mode t)
    (setq ac-sources '(ac-source-words-in-same-mode-buffers ac-source-dictionary ac-source-ghc-mod))))

(add-hook 'find-file-hook 'my-haskell-ac-init)

melpaでghcを入れました。あとは、company-ghciも。

こんなエラーに見舞われたので、ghc-modはcabal installではなくGitHubからビルドしました。

github.com

第2期 第21回 H本読書会 in 秋葉原 メモ #readhbon

readhbon.doorkeeper.jp

Endo

遠藤さんではない。自分自身に返る射を持つ圏のこと。

Data.Monoid

nineties.github.io

独習 Scalaz — 圏論

ドメインとコドメインが同一の対象の射を自己準同型射 (endomorphism) と呼ぶ。

http://nineties.github.io/category-seminar/2.html

実例

-- Endoの実例
import Data.Monoid
import Data.Foldable

main = do
    -- 左から順番に計算していく。
    print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,33] ) 0
    print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,32] ) 0
    print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,34] ) 0
    print $ ((((33*)34+)3*)12+1)

おさらい

P281-P290まで

  • 「モナド」は「アプリカティブファンクター」の強化版(アプリカティブファンクターはファンクターの強化版) どんどん柔軟性が高まる(三兄弟)
  • Maybeに特化したモナドの説明
  • Monad型クラス
Prelude> return "WHAT" :: Maybe String
Just "WHAT"
Prelude> 
  • ピエールの綱渡り(このネタは独習Scalazにも出てくる)
type Birds = Int
type Pole = (Birds, Birds)

-- 鳥
landLeft :: Birds -> Pole -> Pole
landLeft n (left, right) = (left + n, right)
landRight :: Birds -> Pole -> Pole
landRight n (left, right) = (left, right + n)

-- バランス棒
x -: f = f x

main = do
    print $ landLeft 2 (0, 0)
    print $ landLeft 1 (1, 2)
    print $ landRight (-1) (1, 2)
    print $ (0, 0) -: landLeft 1 -: landRight 1 -: landLeft 2

Data.Function

F#にあったものを流用したのが(&) らしい。

Prelude> Prelude.sum $ filter even $ map (+3) [1,2,3]
10

が、こういう書き方が出来るようになるらしい(GHC 7.10の場合)

Prelude> [1,2,3] & map (+3) & filter even & Prelude.sum

落ちるぅうあああ

4羽来た瞬間に落ちるパターンを実装する。具体的には、JustとNothingを使う。

type Birds = Int
type Pole = (Birds, Birds)

-- 鳥
landLeft :: Birds -> Pole -> Maybe Pole
landLeft n (left, right)
    | abs ((left + n) - right) < 4 = Just (left + n, right)
    | otherwise = Nothing
landRight :: Birds -> Pole -> Maybe Pole
landRight n (left, right)
    | abs (left - (right + n)) < 4 = Just (left, right + n)
    | otherwise = Nothing
-- バランス棒
x -: f = f x

main = do
    print $ landLeft 2 (0, 0)
    print $ landLeft 1 (1, 2)
    print $ landRight (-1) (1, 2)
    print $ landRight 10 (0, 3)

でもこういう書き方はできなくなった。

(0, 0) -: landLeft 1 -: landRight 1 -: landLeft 2

なので、実行方法も合わせる必要がある

*Main> :t (landRight 3 >>=)
(landRight 3 >>=) :: (Maybe Pole -> Pole -> b) -> Pole -> b

ピエールの綱渡り 複数の手順の方法

type Birds = Int
type Pole = (Birds, Birds)

-- 鳥
landLeft :: Birds -> Pole -> Maybe Pole
landLeft n (left, right)
    | abs ((left + n) - right) < 4 = Just (left + n, right)
    | otherwise = Nothing
landRight :: Birds -> Pole -> Maybe Pole
landRight n (left, right)
    | abs (left - (right + n)) < 4 = Just (left, right + n)
    | otherwise = Nothing
-- バランス棒
x -: f = f x

main = do
    print $ landLeft 2 (0, 0)
    print $ landLeft 1 (1, 2)
    print $ landRight (-1) (1, 2)
    print $ landRight 10 (0, 3)
    print $ landRight 1 (0, 0) >>= landLeft 2
    -- NothingがまじるとずっとNothing
    print $ Nothing >>= landLeft 2
    -- print $ (0, 0) -: landLeft 1 -: landRight 4 -: landLeft (-1) -: landRight (-2)
    -- の代わりの書き方
    -- returnは必須
    print $ return (0, 0) >>= landRight 2 >>= landLeft 2 >>= landRight 2
    -- ラムダを使った書き方
    print $ return (0, 0) >>= (\x -> landRight 2 x) >>= (\x -> landLeft 2 x) >>= (\x -> landRight 2 x)

アプリカティブとの比較

(+) <$> Just 3 <*> Just 4

アプリカティブだと、こういう書き方が出来ない

(+) <$> Nothing <*> Just 4 <*> Just 4
return (0,0) >>= landLeft 2 >>= landRight 2 >>= landRight 1

演算をどんどんつなげていくことができる。

バナナ

途中でバナナを踏んだら即死するデータ型を作る。 本にはないけど、ついでに、豆腐を踏んだらスタート地点にもどるやつも実装してみる

type Birds = Int
type Pole = (Birds, Birds)

-- 鳥
landLeft :: Birds -> Pole -> Maybe Pole
landLeft n (left, right)
    | abs ((left + n) - right) < 4 = Just (left + n, right)
    | otherwise = Nothing
landRight :: Birds -> Pole -> Maybe Pole
landRight n (left, right)
    | abs (left - (right + n)) < 4 = Just (left, right + n)
    | otherwise = Nothing
-- バランス棒
x -: f = f x
-- バナナ
banana :: Pole -> Maybe Pole
banana _ = Nothing
-- 豆腐
tofu :: Pole -> Maybe Pole
tofu _ = Just (0,0)

main = do
    print $ landLeft 2 (0, 0)
    print $ landLeft 1 (1, 2)
    print $ landRight (-1) (1, 2)
    print $ landRight 10 (0, 3)
    print $ landRight 1 (0, 0) >>= landLeft 2
    -- NothingがまじるとずっとNothing
    print $ Nothing >>= landLeft 2
    -- print $ (0, 0) -: landLeft 1 -: landRight 4 -: landLeft (-1) -: landRight (-2)
    -- の代わりの書き方
    -- returnは必須
    print $ return (0, 0) >>= landRight 2 >>= landLeft 2 >>= landRight 2
    -- ラムダを使った書き方
    print $ return (0, 0) >>= (\x -> landRight 2 x) >>= (\x -> landLeft 2 x) >>= (\x -> landRight 2 x)
    print $ (landRight 3 (1,2) >>= (\x -> landLeft 3 x))
    print $ landRight 3 (1, 2)
    -- バナナと豆腐
    print $ return (0, 0) >>= landLeft 1 >>= banana >>= landRight 1
    print $ return (0, 0) >>= landLeft 1 >>= tofu >>= landRight 1
    print $ return (0, 0) >>= landLeft 1 >>= landRight 1 >>= tofu

モナドを使わない選択

-- モナドを使わない選択
routine :: Maybe Pole
routine = case landLeft 1 (0, 0) of
              Nothing -> Nothing
              Just pole1 -> case landRight 4 pole1 of
                                Nothing -> Nothing
                                Just pole2 -> case landLeft 2 pole2 of
                                                  Nothing -> Nothing
                                                  Just pole3 -> landLeft 1 pole3

こういうふうに書かないといけないので、ネストの嵐になってむっちゃめんどう。

13.5 do記法

main = do
    print $ Just 3 >>= ( \ x -> Just (show x ++ "!"))
    print $ Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Just (show x ++ y)))
    -- print $ Nothing >>= ( \ x -> Just "!" >>= ( \ y -> Just (show x ++ y)))
    -- print $ Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Nothing))
    -- Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Nothing))
-- モナド値を連鎖させた式と等価なものを、ずっと簡潔に表せる記法が do 式

-- doを使わない書き方
foo1 :: Maybe String
foo1 = Just 3
      >>= ( \ x ->
            Just "!" >>= ( \ y ->
                           Just (show x ++ y)))

-- doを使った書き方
foo2 :: Maybe String
foo2 = do
    x <- Just 3
    y <- Just "!"
    Just (show x ++ y)

main = do
    print $ foo1
    print $ foo2

なんとなくわかるけど、自分流にコードをアレンジするの難しいね。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!