Haskellで私のクローン(bot)を書いた

この記事は高専高専abcは今月ではない

ゆきばらです。ソースコードがいっぱいあって長いです。ごめん。

何をしましたか

ゆきばら のコピー(@ykbr__ai)を作りました。アンダーバーは二つあります。
コードはこれです。積んでいたすごいH本をこのままにはしておけず、Haskellの勉強を兼ねてやりました。@hsm_aiの二番煎じ

github.com

環境

OS: Windows 10 Pro

言語: Haskell - stackのバージョン -> 1.91

やることの方針

  1. H本を読む(理解の有無を問わない)
  2. 形態素解析をする
  3. それを使ってマルコフ連鎖で文章生成をする
  4. TwitterAPIを殴打する
  5. 試験運用期間(1週間)を決め、つまらなかったら切る

やった

環境を作る

Haskellにはstack

Home - The Haskell Tool Stack

という便利なビルドツール?パッケージマネージャ?があり、それを使います。

HaskellでTwitterのタイムライン取得とツイート投稿をやってみた を参考にさせて頂き、とりあえずツイートまで漕ぎ付けました。
一応簡単に説明すると、

  • stack new をすると雛型が生成される
  • package.yaml に使うパッケージを記述する。
  • src/Lib.hsapp/Main.hs にコーディングをする

ということでほぼ写経でしたが、アクセストークンをペーストする際に半角スペースが混入し、これで1時間溶かしました。

認証の諸々は分離させておきます。

MeCabをインストールする

MeCabを絶対にインストールしてくれ!!!!!!!!!!!!(1敗)

当然ですが、MeCab本体が無いとどうしようもありません。これに気付かないと2時間が溶けます。ました。

MeCabのインストールには有志作成のこちら(64bit版)を使用させていただきました。
インストールが終わったらPATHを通してあげましょう。 Windowsなので、環境変数Pathに C:\Program Files\MeCab\bin を追加しました。

MeCabには標準でHaskellバインディングがありません。

なので、hsmecabというかの有名なtanakhさんが作成したMeCabHaskellバインディングを少し改良して使います。

とりあえずforkして、依存関係を書き直しました。
そのあと、stack.yaml

extra-deps:
- github: Yukibara/hsmecab
  commit: "687dce1"

extra-include-dirs:
- C:\Program Files\MeCab\sdk
extra-lib-dirs:
- C:\Program Files\MeCab\sdk

ということを書いてあげます。
extra-deps にはstackageにないパッケージを記載するのですが、今回はそこに先程依存関係を書き直したhsmecabを書きます。
extra-include-dirsextra-lib-dirs にはMeCabのヘッダファイルとライブラリがある場所をそれぞれ書きました。

ハマる

ここから地獄のハマり芸が始まります。

PS E:\User\Desktop\ykbr-ai> stack build
Building all executables for `ykbr-ai' once. After a successful build of all of them, only specified executables will be rebuilt.
ykbr-ai-0.1.0.0: build (lib + exe)
Preprocessing library for ykbr-ai-0.1.0.0..
Building library for ykbr-ai-0.1.0.0..
Preprocessing executable 'ykbr-ai-exe' for ykbr-ai-0.1.0.0..
Building executable 'ykbr-ai-exe' for ykbr-ai-0.1.0.0..
Linking .stack-work\dist\7d103d30\build\ykbr-ai-exe\ykbr-ai-exe.exe ...
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xb8ae): `mecab_get_theta' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xb9e9): `mecab_version' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xbc3b): `mecab_set_theta' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xbdee): `mecab_get_all_morphs' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xbfbc): `mecab_nbest_next_tostr' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xcaa4): `mecab_nbest_next_tonode' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xcd7e): `mecab_get_lattice_level' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xceb4): `mecab_new2' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xcfd2): `mecab_destroy' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xd258): `mecab_set_partial' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xd341): `mecab_set_partial' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xd5ae): `mecab_get_partial' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xd77c): `mecab_set_all_morphs' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xda5b): `mecab_strerror' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xddb2): `mecab_sparse_tostr2' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xe13b): `mecab_strerror' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xe460): `mecab_nbest_sparse_tostr2' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xe7f3): `mecab_strerror' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xea22): `mecab_nbest_init2' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xecfb): `mecab_strerror' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xef82): `mecab_sparse_tonode2' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xf2b4): `mecab_set_lattice_level' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xf572): `mecab_strerror' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xf762): `mecab_destroy' に対する定義されていない参照です
E:\User\Desktop\ykbr-ai\.stack-work\install\82b85939\lib\x86_64-windows-ghc-8.4.4\mecab-0.4.0-36pNwJDNccJIAIpRtYgh7y/libHSmecab-0.4.0-36pNwJDNccJIAIpRtYgh7y.a(MeCab.o):fake:(.text+0xf828): `mecab_new' に対する定義されていない参照です
collect2.exe: error: ld returned 1 exit status
`gcc.exe' failed in phase `Linker'. (Exit code: 1)

--  While building package ykbr-ai-0.1.0.0 using:
      C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_2.2.0.1_ghc-8.4.4.exe --builddir=.stack-work\dist\7d103d30 build lib:ykbr-ai exe:ykbr-ai-exe --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

ふふw

解決方法

extra-lib-dirs:
- C:\Program Files\MeCab\sdk

extra-lib-dirs:
- C:\Program Files\MeCab\sdk
- C:\Program Files\MeCab\bin

libmecab.dllC:\Program Files\MeCab\bin にあったのでそれを指定しただけです。
たったこれだけ。なんと1日を溶かしました。ウケる。

それと、前述したPATHを通さないとstack exec {project-name} したときに何も表示されることなく(エラー一行生えない)終わるので、しっかり通しましょう(一敗)。

ここまで「Botをつくる!」と言ってから5日が経過!!!!!!!!!!!!!!!!

コーディングをする

MeCabのテストをしてあげる

とりあえずハマりから抜けたか確認してみましょう。

import Data.Text.IO as TIO

import Text.MeCab

someFunc :: IO ()
someFunc = do
  let text = "頼むので動いてくださいお願いします"
  mecab  <- new2 ""
  result <- parse mecab text
  TIO.putStrLn $ result

これを実行すると

頼む    動詞,自立,*,*,五段・マ行,基本形,頼む,タノム,タノム
ので    助詞,接続助詞,*,*,*,*,ので,ノデ,ノデ
動い    動詞,自立,*,*,五段・カ行イ音便,連用タ接続,動く,ウゴイ,ウゴイ
て      助詞,接続助詞,*,*,*,*,て,テ,テ
ください        動詞,非自立,*,*,五段・ラ行特殊,命令i,くださる,クダサイ,クダサイ
お願い  名詞,サ変接続,*,*,*,*,お願い,オネガイ,オネガイ
し      動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス

良さそうですね。これが出なかったあなたはまだハマっています。トンネル効果でもなんでもいいので抜け出しましょう。

@ykbr_のツイートを取得する

自分のツイートを取得しました。
これはソースコード載せたところでなあという感じなのでリポジトリ見てください(丸投げv0.2)。
いよいよ、これを引数にとってマルコフ連鎖させます。

マルコフ連鎖する

こちらのサイトを死ぬほど参考にしながらマルコフ連鎖をしました。

Haskellはデータ型を作るのが楽なので、

data Word = Begin|Middle String|End deriving (Eq,Show, Generic)

という感じで単語の管理をしました。詳しくはソースを見てください(丸投げの時代)。

#はじめてのツイート

感想

環境構築がつらかった。
型まわりのエラーでめちゃくちゃハマってHaskellやめちまえになりました。
でもなんとなく書いていて楽しさがあるので、まずはH本を読もうと思います。

あと高専祭でライブコーディングできたのは良かったですね。

今後

とりあえずRTを含んでしまっているのでそれを除外します。
あと自動フォロバを早くつけてくれ。

単語をDBにシュッとやれればかっこいいと思うけどその辺は気が向いたらやろうかなって思います。

おわり