1. brackss1

    Posted

    brackss1
Changes in title
+Haskell入門者がライブラリを触っちゃう!?
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,143 @@
+#はじめに
+これは[AdventCalendar2017](https://qiita.com/advent-calendar/2017/haskell)の22日目の記事です。
+はじめまして。@brackss1です。
+「すごいH本」を読み終わって何か作りたくなりました。そこで目を付けたのが**Web開発**です。有名なWebFrameworkといえば *Ruby on Rails, Node.js, Go on Revel, Django* などが思いつきますが、Haskellにも *Yesod, Spock* など[wiki](https://wiki.haskell.org/Web/Frameworks)に紹介されているだけでも14個のライブラリがあります。この中から今回は**scotty**を使いました。
+#環境
+Haskell使うには**Stack**(パッケージ管理)で神。
+エディターは**VSCode**を使いました。Haskero拡張インストールしてinteroをセットすれば補完できるのでなんとかなります。
+せっかくなのでインターネット上にあっぷしたい。お手軽なのは**GitHub.IO**ですが静的サイトしか公開できない(DBが使えない)ので、**Heroku**を使います。無料で使えるので選びました。(だいぶ制限されますが)
+
+#Herokuについてちょっと
+**PaaS**(Platform as a Service)。git&herokuコマンドでコマンドラインで操作できるので楽しい。以上。
+#ライブラリ…
+WebAppの要素は主に3つあると思って…
+1. Routing
+2. HTML+CSS+Javascript
+3. DataBase
+YesodのようなフルスタックのWebFrameworkもありますが、Haskellはライブラリが豊富なのでこれらに対応するものが独立してあります。
+
+#Routing
+WebサイトのURLとそこで表示するページを結びつけます。はじめに書いたように**scotty**を使います。詳しいドキュメントは[Hackage](https://hackage.haskell.org/package/scotty)でも見てください。
+サンプルは実行してhttp://localhost:3000 にアクセスしてください。
+
+```hs:sample
+{-# LANGUAGE OverloadedStrings #-}
+
+import Web.Scotty
+
+main :: IO()
+
+main = scotty 3000 $ do
+ get "/" $ html "<h1>Hello!</h1>"
+```
+
+ただHello!と表示されます。POST通信はログイン機能で披露したいので、HTMLファイルのパースを紹介した後にしたいと思います。
+外部鯖(ここではHeroku)に公開したい場合は次のようにします。
+
+```hs
+getPort :: Maybe Int -> Int
+getPort (Just n) = n
+getPort Nothing = 3000
+
+port <- lookupEnv "PORT"
+scotty (getPort $ read <$> port) $ do
+```
+
+#HTMLパース&レンダリング
+HTML+CSS+Javascriptの書き方はこの記事では書きません。
+実際に表示するためのhtmlをパース&レンダリングします。数あるライブラリの中で**ede**を選択しました。**aeson**のJSONパーサが利用できるので。
+
+```html:index
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>{{ title }}</title>
+ </head>
+ <body>
+ <h1>{{ title }}</h1>
+ <ol>
+ {% for food in foods %}
+ <li>{{ food.value }}</li>
+ {% endfor %}
+ </ol>
+ </body>
+</html>
+```
+```hs:parse&render
+{-# LANGUAGE OverloadedStrings #-}
+
+import Web.Scotty
+import Text.EDE
+import Data.Aeson
+import Data.Text(Text)
+
+main :: IO()
+
+main = do
+
+ path <- eitherParseFile "./html/index.html"
+
+ let env = fromPairs [("title" :: Text) .= ("好きな食べ物TOP3" :: Text)
+ ,("foods" :: Text) .= (["フォー","餃子","石焼ビビンバ"] :: [Text])]
+
+ let txt = either error id $ path >>= (`eitherRender` env)
+
+ scotty 3000 $ do
+ get "/" $ html txt
+```
+
+自作のデータ型を使いたい場合は…
+
+```hs
+data Food = Food {name :: Text, from :: Text}
+
+foods :: [Food]
+foods = [Food "curry and rice" "India",
+ Food "hamburger" "America",
+ Food "ramen" "China"]
+instance ToJSON Food
+```
+
+`ToJSON`のinstanceにすればOKです。
+
+#DBをさわる
+リレーショナル・データベースとして有名なのはMySQLとPostgreSQLですが、Herokuで使えるのが後者だけということなのでそれを選びました。ライブラリは@khibinoさんの**haskell-relational-record**(以後HRRと略)を使います。(cabalファイルに書くときは**relational-query**です。とりま**sqlite3**をインストールしておいてください。
+
+```hs:sample
+import Data.Int(Int32)
+import Database.Relational.Query
+
+hello :: Relation () (Int32, String)
+hello = relation $ return $ value 0 >< value "Hello"
+
+world :: Relation () (Int32, String)
+world = relation $ return $ value 0 >< value "World"
+
+helloworld :: Relation () (Int32, String, String)
+helloworld = relation $ do
+ h <- query hello
+ w <- query world
+ on $ h ! fst' .=. w ! fst'
+ return $ (,,) |$| h ! fst' |*| h ! snd' |*| w ! snd'
+
+main :: IO ()
+main = putStrLn $ show helloworld ++ ";"
+```
+```bash:command
+stack build&stack exec sample-exe | sqlite3
+```
+```bash:result
+0|Hello|World
+```
+公式ドキュメントほぼまんまですw。ここでは仮想のDBを作成して作業しています。
+次は実際のDBをいじりましょう!といきたいですが…
+**TemplateHaskell**の知識が少々必要になります。
+残念ながらWriterにはこの知識がないのでテキトーなことは言えません。
+実際にDBを操作するときは、`defineTable`マクロでもろもろ自動導出してくれるのでかなり楽っぽいです。先ほどの操作を実際に発行するときは`runQuery`で実行します。
+以上です。ここらへんはぼくもちんぷんかんぷんです(すいません…)
+#おわり
+とりあえず「Haskellでなんかしたい」みたいなのは叶えられました。
+ここではそれぞれのライブラリについて断片的に紹介して終わりにしました。
+haskell-jpのslackで質問に答えくださったみなさんには感謝しています。
+コメントorマサカリは https://twitter.com/seatofhorse まで。
+おわり。