IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

Servant API の変遷

HasServerのroute関数の変遷

class HasServer layout where
  type ServerT layout (m :: * -> *) :: *
  route ::  *********
version implementation
0.2.1–0.4.0 route :: Proxy layout -> Server layout -> RoutingApplication
0.5–0.6 route :: Proxy layout -> Context context -> Delayed (Server layout) -> Router
0.7–0.10 route :: Proxy api -> Context context -> Delayed env (Server api) -> Router env

Haskellの名前空間をまとめる実装

下記のようなコードがありVertex3のドキュメントを確認しようとおもったのですが、上手くドキュメントが見つけられませんでした。

import Graphics.Rendering.OpenGL as GL

GL.vertex $ (GL.Vertex3 (-1) (-1)  0 :: GL.Vertex3 GL.GLfloat)

Graphics.Rendering.OpenGLのページをみてもVertex3は存在しません。

Graphics.Rendering.OpenGL

しかし、ghciにて確認すると、Graphics.Rendering.OpenGLに存在するようにみえます。

*Main> :i Graphics.Rendering.OpenGL.Vertex3
data Vertex3 a = Vertex3 !a !a !a
    -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Bounded a => Bounded (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Eq a => Eq (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Functor Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Ord a => Ord (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Read a => Read (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Show a => Show (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Applicative Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Foldable Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Traversable Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance TrimmingPoint Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GLU.NURBS’
instance VertexAttribComponent a => VertexAttrib (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.VertexSpec’
instance VertexComponent a => Vertex (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.VertexSpec’
instance UniformComponent a => Uniform (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Shaders.Uniform’
instance WindowPosComponent a => WindowPos (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.RasterPos’
instance RasterPosComponent a => RasterPos (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.RasterPos’
instance ControlPoint Vertex3
  -- Defined in ‘OpenGL-3.0.1.0:Graphics.Rendering.OpenGL.GL.ControlPoint’
*Main> 

よく読むと、-- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’とあるので、実際はTensorパッケージに存在しているようです。ghciで確認すると、確かにあるようです。

*Main> :i Graphics.Rendering.OpenGL.GL.Tensor.Vertex3
data Vertex3 a = Vertex3 !a !a !a
    -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Bounded a => Bounded (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Eq a => Eq (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Functor Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Ord a => Ord (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Read a => Read (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Show a => Show (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Applicative Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Foldable Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance [safe] Traversable Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Tensor’
instance TrimmingPoint Vertex3
  -- Defined in ‘Graphics.Rendering.OpenGL.GLU.NURBS’
instance VertexAttribComponent a => VertexAttrib (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.VertexSpec’
instance VertexComponent a => Vertex (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.VertexSpec’
instance UniformComponent a => Uniform (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.Shaders.Uniform’
instance WindowPosComponent a => WindowPos (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.RasterPos’
instance RasterPosComponent a => RasterPos (Vertex3 a)
  -- Defined in ‘Graphics.Rendering.OpenGL.GL.RasterPos’
instance ControlPoint Vertex3
  -- Defined in ‘OpenGL-3.0.1.0:Graphics.Rendering.OpenGL.GL.ControlPoint’
*Main> 

不思議に思いソースコードを確認したところ、名前空間をまとめているようです。

https://github.com/haskell-opengl/OpenGL/blob/master/src/Graphics/Rendering/OpenGL.hs

module Graphics.Rendering.OpenGL (
 ...
     module Graphics.Rendering.OpenGL.GL
   , module Graphics.Rendering.OpenGL.GLU
 ...
) where

https://github.com/haskell-opengl/OpenGL/blob/master/src/Graphics/Rendering/OpenGL/GL.hs

module Graphics.Rendering.OpenGL.GL (
 ...
   module Graphics.Rendering.OpenGL.GL.Tensor,
 ...
) where

https://github.com/haskell-opengl/OpenGL/blob/master/src/Graphics/Rendering/OpenGL/GL/Tensor.hs

module Graphics.Rendering.OpenGL.GL.Tensor (
   Vertex1(..), Vertex2(..), Vertex3(..), Vertex4(..),
   Vector1(..), Vector2(..), Vector3(..), Vector4(..)
) where

Javaでいうimport foo.bar.*のようなワイルドカードを使ってインポートする機能がhaskellにはないためなのでしょうか。ワイルドカードをつかうと曖昧になるので機能としてないみたいです。

stackoverflow.com

ServantのAPIからHandlerへの型の流れを確認する

Servantチュートリアルでは、2.2.3でチートシートのように説明されています。 https://media.readthedocs.org/pdf/haskell-servant/v0.6/haskell-servant.pdf

combinator handelrのパラメータ 補足
Capture “something” a a
QueryParam “something” a Maybe a
Header “something” a Maybe a
QueryFlag “something” Bool
QueryParams “something” [a]
ReqBody contentTypes a a
Delete, Get, Patch, Post, Put ExceptT ServantErr IO これはハンドラそのも

この点の理解ができていなかったので、ServantでHandlerのパラメータどのように作られるか型を辿って確認してみました。

ポイントはtype familyで指定される型の対応を地道に辿っていくことです。

Servant Type Transition from API to Handler

Learn Physics の導入

Learn Physics

learn-physics: Haskell code for learning physics

stackでインストールしてみます。

bar:graphics foo$ stack new graphics-work01
Downloading template "new-template" to create project "graphics-work01" in graphics-work01/ ...

The following parameters were needed by the template but not provided: author-email, author-name, category, copyright, github-username
You can provide them in /Users/foo/.stack/config.yaml, like this:
templates:
  params:
    author-email: value
    author-name: value
    category: value
    copyright: value
    github-username: value
Or you can pass each one as parameters like this:
stack new graphics-work01 new-template -p "author-email:value" -p "author-name:value" -p "category:value" -p "copyright:value" -p "github-username:value"

Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- graphics-work01/graphics-work01.cabal

Selecting the best among 10 snapshots...

Downloaded lts-8.11 build plan.
Fetching package index ...remote: Counting objects: 6105, done.
remote: Compressing objects: 100% (4824/4824), done.
remote: Total 6105 (delta 1641), reused 5005 (delta 1120), pack-reused 0
Receiving objects: 100% (6105/6105), 1.80 MiB | 2.27 MiB/s, done.
Resolving deltas: 100% (1641/1641), completed with 677 local objects.
From https://github.com/commercialhaskell/all-cabal-hashes
 + 94fd2e6...dbe78f6 hackage    -> origin/hackage  (forced update)
 - [tag update]      current-hackage -> current-hackage
Fetched package index.
Populated index cache.
Did not find .cabal file for unbounded-delays-0.1.0.10 with Git SHA of f02d37e48a454a6d91bbc9106222ea7fdd7764d2
Right Nothing
* Matches lts-8.11

Selected resolver: lts-8.11
Initialising configuration using resolver: lts-8.11
Total number of user packages considered: 1
Writing configuration to file: graphics-work01/stack.yaml
All done.

Cabalの編集

executable graphics-work01-exe
  hs-source-dirs:      app
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , graphics-work01
                     , learn-physics

stack.yamlの編集をします。

# Dependency packages to be pulled from upstream that are not in the resolver
# (e.g., acme-missiles-0.3)
extra-deps: [
      learn-physics-0.6.0.2
    , not-gloss-0.7.7.0
    , spatial-math-0.2.7.0
]

上記のstack.yamlの設定をしないでstack buildすると、エラーとなります。

bar:graphics-work01 foo$ stack build
While constructing the BuildPlan the following exceptions were encountered:

--  Failure when adding dependencies:
      learn-physics: needed (-any), stack configuration has no specified version (latest applicable is 0.6.0.2)
    needed for package graphics-work01-0.1.0.0

--  While attempting to add dependency,
    Could not find package learn-physics in known packages

Recommended action: try adding the following to your extra-deps in /Users/foo/work03/graphics/graphics-work01/stack.yaml
- learn-physics-0.6.0.2

You may also want to try the 'stack solver' command

このエラーを解決するにはstack solverを実行します。そうすると、修正方法を教えてくれます。これが上述の設定になります。

bar:graphics-work01 foo$ stack solver
Using configuration file: stack.yaml
Using cabal packages:
- graphics-work01.cabal

Using resolver: lts-8.11
Using compiler: ghc-8.0.2
Asking cabal to calculate a build plan...
Trying with packages from lts-8.11 as hard constraints...
Successfully determined a build plan with 3 external dependencies.

The following changes will be made to stack.yaml:
* Resolver is lts-8.11
* Dependencies to be added
    extra-deps:
    - learn-physics-0.6.0.2
    - not-gloss-0.7.7.0
    - spatial-math-0.2.7.0

To automatically update stack.yaml, rerun with '--update-config'

初回のstack buildで依存関係を解決したライブラリがインストールされます。

bar:graphics-work01 foo$ stack build
graphics-work01-0.1.0.0: unregistering (missing dependencies: learn-physics)
ObjectName-1.1.0.1: download
ObjectName-1.1.0.1: configure

途中省略[f:id:naotoogawa:20170416134218p:plain]

learn-physics-0.6.0.2: build
learn-physics-0.6.0.2: copy/register
graphics-work01-0.1.0.0: configure
Configuring graphics-work01-0.1.0.0...
graphics-work01-0.1.0.0: build
Preprocessing library graphics-work01-0.1.0.0...
[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Lib.o )
ld: warning: directory not found for option '-L/opt/local/lib/'
Preprocessing executable 'graphics-work01-exe' for graphics-work01-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/graphics-work01-exe/graphics-work01-exe-tmp/Main.o ) [Lib changed]
Linking .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/graphics-work01-exe/graphics-work01-exe ...
ld: warning: directory not found for option '-L/opt/local/lib/'
graphics-work01-0.1.0.0: copy/register
Installing library in
/Users/foo/work03/graphics/graphics-work01/.stack-work/install/x86_64-osx/lts-8.11/8.0.2/lib/x86_64-osx-ghc-8.0.2/graphics-work01-0.1.0.0-Df1PA4o0N7R3GcxbM23sV6
Installing executable(s) in
/Users/foo/work03/graphics/graphics-work01/.stack-work/install/x86_64-osx/lts-8.11/8.0.2/bin
Registering graphics-work01-0.1.0.0...
Completed 61 action(s).
bar:graphics-work01 foo$ ls

サンプルを取得します。

bar:app foo$ curl -O https://raw.githubusercontent.com/walck/learn-physics/master/examples/src/LorentzForceSimulation.hs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1464  100  1464    0     0   4636      0 --:--:-- --:--:-- --:--:--  4647
bar:app foo$ ls
LorentzForceSimulation.hs   Main.hs             eFieldLine2D.hs
bar:app foo$

cabalファイルに、main関数があるファイルの指定と、依存関係ライブラリの指定を追加します。

executable graphics-work01-exe
  hs-source-dirs:      app
  main-is:             LorentzFoArceSimulation.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , graphics-work01
                     , learn-physics
                     , not-gloss
                     , spatial-math
                     , gloss
  default-language:    Haskell2010

ビルドします。

bar:graphics-work01 foo$ stack build
graphics-work01-0.1.0.0: build
Preprocessing library graphics-work01-0.1.0.0...
Preprocessing executable 'graphics-work01-exe' for graphics-work01-0.1.0.0...
[1 of 1] Compiling Main             ( app/LorentzForceSimulation.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/graphics-work01-exe/graphics-work01-exe-tmp/Main.o )
Linking .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/graphics-work01-exe/graphics-work01-exe ...
ld: warning: directory not found for option '-L/opt/local/lib/'
graphics-work01-0.1.0.0: copy/register
Installing library in
/Users/foo/work03/graphics/graphics-work01/.stack-work/install/x86_64-osx/lts-8.11/8.0.2/lib/x86_64-osx-ghc-8.0.2/graphics-work01-0.1.0.0-Jws64xXpAJx1AXCetAcS6y
Installing executable(s) in
/Users/foo/work03/graphics/graphics-work01/.stack-work/install/x86_64-osx/lts-8.11/8.0.2/bin
Registering graphics-work01-0.1.0.0...

実行します。

bar:graphics-work01 foo$ stack exec graphics-work01-exe
bar:graphics-work01 foo$

f:id:naotoogawa:20170416134218p:plain