Edited at

servant-haskellをCloud Runにのせて結び目不変量を求めるWebアプリを作る

夏休みですね。1

みなさん夏休みの工作の進捗はいかがでしょうか?

servant-haskellとVueを触りたくなり、お絵かきアプリを作ってみました。


この記事で紹介すること


  • haskellを使った位相幾何学アプリケーションの設計

  • Cloud Run2を使ったservant-haskellアプリのデプロイ

経験が浅いのでトンチンカンなことを言っているかもしれませんが、ご容赦ください。


対象とする人

エンジニア・数学徒など、どなたでも

インフラ周り、サーバサイドのアルゴリズムからフロントのUIまで、なんでもコメントいただけると嬉しいです。

フロント側の設計、実装は別記事 にまとめました


作成物のデモ


設計

フロント側(Vue.js)でお絵かき機能を実装し、お絵かきしたデータをservant側に送って5カウフマンブラケットを計算してフロントに返す。


実装

servant-haskellのわかりやすい入門は@lotzさんの【型レベルWeb DSL】 Servantの紹介 をご参照ください。


サーバー

まず上のような結び目の図(射影図などと呼ばれます)からカウフマンブラケットを計算するために必要なデータ構造を考えてみましょう。

射影図をじっと見つめていると結び目たちが「交点を頂点としたグラフ」に見えてくると思います。これをHaskellの型を使って実装すると次のような感じになると思います。

data Front = Front {tagf :: Int} deriving (Show,Eq)

data Back = Back {tagb :: Int} deriving (Show,Eq)
data Intersection = InterSection {edges :: (Front,Front,Back,Back)} | Trivial deriving (Show,Eq)
type Link = [Intersection]

あとはいい感じにWikipediaにある通りに再帰でカウフマンブラケットを求めれば良いです。


フロント

お絵かきして計算に必要なデータをajaxでservantに送れるようにします。

詳細は別記事にて


デプロイ

以下のDockerfileをcloud buildでビルドした後、Cloud Runの画面かgcloudコマンドでデプロイできます。


  • Dockerから外部に通ずるポートを環境変数PORTに入れる

  • 80,443以外のポートを指定する

ことに気をつければOKです。

Dockerfileのビルドを2回にしなくともMulti-stageのDockerfileをCloud Buildでビルドするコツにmulti-stagedなDockerfileのビルドを一発でstage毎に別リポジトリにpushできる方法が紹介されていますが、未着手です。

Dockerfile(ビルド用)

FROM haskell:8.6.5

ADD https://api.github.com/repos/ayanamizuta/jones/git/refs/heads/master version.json
RUN git clone https://github.com/ayanamizuta/jones.git

WORKDIR ./jones
RUN stack setup
RUN stack build
RUN stack --local-bin-path /sbin install

Dockerfile(デプロイ用)

FROM びるど

WORKDIR ./jones
RUN mkdir bin
COPY /sbin/jones ./bin/
EXPOSE 8080
ENV PORT 8080
CMD ["bin/jones"]


参考にした記事等

【型レベルWeb DSL】 Servantの紹介

Multi-stageのDockerfileをCloud Buildでビルドするコツ


わからなかった事


  • 以下のようなDockerfileでデプロイしようとしたところ、entrypointの stack run 起動時にghcをインストールしてしまうようでした(現在のデプロイはバイナリを叩いて動いています)。stack build時に(起動時にinstallされてしまうghcと同じversionの)ghcがinstallされるのに、なぜ...

FROM びるど

EXPOSE 8080
ENV PORT 8080
CMD ["stack","run"]





  1. 仕事の最繁忙期でした(しみじみ)。 



  2. 当初GAEを勉強したくてGAEにデプロイしようとしたのですが、個人で利用するには料金がそこそこするのでCloud Runにしました。この記事と同じ方法でGAEにもデプロイできることを確認しています。 



  3. 厳密に言うとこれは結び目不変量ではないです。結び目不変量であるところのJones多項式を求める機能まで作ろうとしましたが、デプロイに時間がかかりpendingしました... 



  4. もっさりしますが、リバースプロキシをfirebase functionsで立てたためです(リージョンがus-centralしかない...) 



  5. DB使うわけでもないのでサーバーサイドの実装はいらないんですが、haskell使いたかったしGAEへのデプロイもやってみたかったので今回の構成にしました。