IT練習ノート

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

Haskellで地理情報を扱うためにGeosパッケージのインストール(2018年02月時)

gitからモジュールを取得しておきます。

git clone https://github.com/ewestern/geos.git

開発中のライブラリから使用したいので、そのプロジェクトにて、普通にインストールしようとすると、geosライブラリが不足しているためエラーになりました。

$ cabal install geos
Warning: --root-cmd is no longer supported, see
https://github.com/haskell/cabal/issues/3353 (if you didn't type --root-cmd,
comment out root-cmd in your ~/.cabal/config file)
Resolving dependencies...
Notice: installing into a sandbox located at
/Users/.cabal-sandbox
Downloading geos-0.1.1.1...
Configuring geos-0.1.1.1...
Failed to install geos-0.1.1.1
Build log ( /.cabal-sandbox/logs/ghc-8.0.1/geos-0.1.1.1-BMEKj1bfr4oGwvlkBjY7fl.log ):
cabal: Entering directory '/var/folders/hw/p4bp49hd7v9_1j60sjvmhqnr0000gn/T/cabal-tmp-25906/geos-0.1.1.1'
Configuring geos-0.1.1.1...
cabal: Missing dependency on a foreign library:
* Missing (or bad) header file: geos_c.h
* Missing C library: geos_c
This problem can usually be solved by installing the system package that
provides this library (you may need the "-dev" version). If the library is
already installed but in a non-standard location then you can use the flags
--extra-include-dirs= and --extra-lib-dirs= to specify where it is.
If the header file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.
cabal: Leaving directory '/var/folders/hw/p4bp49hd7v9_1j60sjvmhqnr0000gn/T/cabal-tmp-25906/geos-0.1.1.1'
cabal: Error: some packages failed to install:
geos-0.1.1.1-BMEKj1bfr4oGwvlkBjY7fl failed during the configure step. The
exception was:
ExitFailure 1

geosをインストールします。

$ brew install geos
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 3 taps (caskroom/cask, homebrew/core, homebrew/php).
==> New Formulae
calicoctl                         dynare                            gpredict                          libdill                           odpi                              terraforming
clblast                           fruit                             grv                               libsbol                           openimageio                       tomcat@8
dashing                           futhark                           homebrew/php/phpunit@6.5          ocrmypdf                          srt                               webtorrent-cli
==> Updated Formulae
awscli ✔              c-ares                emscripten            git                   iperf3                libav                 node@6                plank                 statik
acmetool              camlp5                erlang                git-archive-all       irssi                 libpqxx               ocaml                 postgresql@9.4        stlink
advancecomp           chakra                etcd                  glpk                  jenkins               liquibase             ocaml-num             qemu                  supervisor
allure                chronograf            feh                   gnutls                jenkins-lts           logstalgia            ocamlsdl              qt                    suricata
angular-cli           cimg                  ffmpeg@2.8            go                    jfrog-cli-go          lumo                  ooniprobe             quicktype             taisei
aqbanking             clhep                 fio                   godep                 joplin                lynis                 opendetex             recon-ng              twarc
aws-elasticbeanstalk  console_bridge        flow                  gomplate              juju                  lzip                  osm2pgrouting         rust                  typescript
azure-cli             coq                   fluent-bit            googler               just                  magic-wormhole        paket                 rustup-init           urdfdom
bareos-client         coreos-ct             fn                    gource                jvgrep                mame                  pandoc-citeproc       s-nail                vala
bazel                 dartsim               forego                grakn                 kallisto              mariadb               pc6001vx              sagittarius-scheme    vdirsyncer
bcftools              ddrescue              freetds               gtk+3                 kedge                 mas                   pdns                  sbt@0.13              vim
binaryen              diamond               frugal                gutenberg             knot                  math-comp             percona-server@5.6    sceptre               wtf
bitrise               dmd                   gcovr                 heroku                knot-resolver         mdcat                 pgpool-ii             simg2img              xtensor
blast                 dnscrypt-wrapper      gdnsd                 homebrew/php/envoy    kobalt                memcached             picard-tools          singular
bro                   dub                   gecode                homebrew/php/phpunit  kompose               metricbeat            pilosa                skafos
buildapp              duck                  geth                  hugo                  leptonica             mpv                   pipenv                sslh
==> Deleted Formulae
homebrew/php/phpunit@5.7                                                                               tomcat@8.0

==> Downloading https://homebrew.bintray.com/bottles/geos-3.6.2.yosemite.bottle.tar.gz
######################################################################## 100.0%
==> Pouring geos-3.6.2.yosemite.bottle.tar.gz
🍺  /usr/local/Cellar/geos/3.6.2: 402 files, 8.7MB

再度geosをインストールするがヘッダファイルが見つからずエラーとなります。

$ cabal install geos
Warning: --root-cmd is no longer supported, see
https://github.com/haskell/cabal/issues/3353 (if you didn't type --root-cmd,
comment out root-cmd in your ~/.cabal/config file)
Resolving dependencies...
Notice: installing into a sandbox located at
/.cabal-sandbox
Configuring geos-0.1.1.1...
Building geos-0.1.1.1...
Failed to install geos-0.1.1.1
Build log ( /Users/.cabal-sandbox/logs/ghc-8.0.1/geos-0.1.1.1-BMEKj1bfr4oGwvlkBjY7fl.log ):
cabal: Entering directory '/var/folders/hw/p4bp49hd7v9_1j60sjvmhqnr0000gn/T/cabal-tmp-27304/geos-0.1.1.1'
Configuring geos-0.1.1.1...
Preprocessing library for geos-0.1.1.1..
Internal.hsc:9:10: fatal error: 'noticehandlers.h' file not found
#include "noticehandlers.h"
         ^
1 error generated.
compiling dist/dist-sandbox-ce0620c0/build/Data/Geometry/Geos/Raw/Internal_hsc_make.c failed (exit code 1)
command was: /usr/bin/gcc -c dist/dist-sandbox-ce0620c0/build/Data/Geometry/Geos/Raw/Internal_hsc_make.c -o dist/dist-sandbox-ce0620c0/build/Data/Geometry/Geos/Raw/Internal_hsc_make.o -m64 -fno-stack-protector -m64 -fno-stack-protector -m64 -D__GLASGOW_HASKELL__=800 -Ddarwin_BUILD_OS=1 -Dx86_64_BUILD_ARCH=1 -Ddarwin_HOST_OS=1 -Dx86_64_HOST_ARCH=1 -Icbits -fPIC -Idist/dist-sandbox-ce0620c0/build/autogen -Idist/dist-sandbox-ce0620c0/build/global-autogen -include dist/dist-sandbox-ce0620c0/build/autogen/cabal_macros.h -I/Users/.cabal-sandbox/lib/x86_64-osx-ghc-8.0.1/vector-0.12.0.1-JOtbAphig5lG2Gp1CUS1Dj/include -I/Users/.cabal-sandbox/lib/x86_64-osx-ghc-8.0.1/primitive-0.6.2.0-3HSsNCfUEEE4fjqDYVydYZ/include -I/Library/Frameworks/GHC.framework/Versions/8.0.1-x86_64/usr/lib/ghc-8.0.1/bytestring-0.10.8.1/include -I/Library/Frameworks/GHC.framework/Versions/8.0.1-x86_64/usr/lib/ghc-8.0.1/base-4.9.0.0/include -I/Library/Frameworks/GHC.framework/Versions/8.0.1-x86_64/usr/lib/ghc-8.0.1/integer-gmp-1.0.0.1/include -I/Library/Frameworks/GHC.framework/Versions/8.0.1-x86_64/usr/lib/ghc-8.0.1/include -I/Library/Frameworks/GHC.framework/Versions/8.0.1-x86_64/usr/lib/ghc-8.0.1/include/
cabal: Leaving directory '/var/folders/hw/p4bp49hd7v9_1j60sjvmhqnr0000gn/T/cabal-tmp-27304/geos-0.1.1.1'
cabal: Error: some packages failed to install:
geos-0.1.1.1-BMEKj1bfr4oGwvlkBjY7fl failed during the building phase. The
exception was:
ExitFailure 1

回避策として、ヘッダファイルを直接指定します。

$ cabal install geos --extra-include-dirs=/Users/geos/cbits

途中省略

[14 of 15] Compiling Data.Geometry.Geos.STRTree ( src/Data/Geometry/Geos/STRTree.hs, dist/dist-sandbox-d1b569cc/build/Data/Geometry/Geos/STRTree.o )

src/Data/Geometry/Geos/STRTree.hs:7:1: error:
    Failed to load interface for ‘Data.Geometry.Geos.Raw.STRTree’
    Use -v to see a list of the files searched for.
cabal: Leaving directory '/var/folders/hw/p4bp49hd7v9_1j60sjvmhqnr0000gn/T/cabal-tmp-48078/geos-0.1.1.1'
cabal: Error: some packages failed to install:
geos-0.1.1.1-GIstYXM1nrr5kUQOaLl4x4 failed during the building phase. The
exception was:
ExitFailure 1
$

Failed to load interface for ‘Data.Geometry.Geos.Raw.STRTree’となってしまい、cabal経由でのインストールは諦めました。先ほどcloneしたところで、ライブラリを作ることとします。

ここで、geos.cabalファイルを修正します。たぶんData.Geometry.Geos.Raw.STRTreeの指定がother-modulesが必要なようです。

@@ -56,6 +58,7 @@ Library
     , Data.Geometry.Geos.Raw.Buffer
     , Data.Geometry.Geos.Raw.Prepared
     , Data.Geometry.Geos.Raw.Internal
+    , Data.Geometry.Geos.Raw.STRTree

使う側のプロジェクトにて

cabal sandbox add-source geos  

をして、cabalファイルの依存関係に``geos```を追加ました。

これでコンパイルが通るようになりました。

関数のコンテキストの型はユニークに解決される

言われてみれば当たり前なのですが、これに嵌りました。

Num型を複数とる関数があって、Int型やDouble型などいろいろパラメータに与えたかったのですが、コンパイルエラーがとれませんでした。問題点をシンプルな例で示すと以下のようになります。

Num型を複数とる関数を定義します。数値のリストを2つとり、それぞれの要素を掛け合わせて、合計を取ります。

*Main> let sumtimes' = \xs ys -> sum $ zipWith (*) xs ys
*Main> :t sumtimes'
sumtimes' :: Num a => [a] -> [a] -> a

普通に動きます。

*Main> sumtimes' [1,2,3] [1,2,3]

<interactive>:4:1: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Integer’
        (Num a0) arising from a use of ‘it’ at <interactive>:4:1-25
        (Show a0) arising from a use of ‘print’ at <interactive>:4:1-25
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it
14
*Main> sumtimes' [1.0,2.0,3.0] [1.0,2.0,3.0]

<interactive>:5:1: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Double’
        (Fractional a0) arising from a use of ‘it’ at <interactive>:5:1-37
        (Show a0) arising from a use of ‘print’ at <interactive>:5:1-37
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it
14.0

型が曖昧で、ワーニングが出ていますが、型を明示的に指定すれば、ワーニングはなくなります。

*Main> sumtimes' [1::Int,2,3] [1,2,3]
14
*Main> sumtimes' [1,2,3] [1,2::Double,3]
14.0

ここまでは良いのですが、2つのバラメータに別の数値型のリストを与えた時は、コンパイルエラーになります。ここに気づかず時間を取られていまいました。

*Main> sumtimes' [1::Int,2,3] [1::Double,2,3]

<interactive>:8:25: error:
    • Couldn't match expected type ‘Int’ with actual type ‘Double’
    • In the expression: 1 :: Double
      In the second argument of ‘sumtimes'’, namely ‘[1 :: Double, 2, 3]’
      In the expression: sumtimes' [1 :: Int, 2, 3] [1 :: Double, 2, 3]
*Main>

IntIntegerでもコンパイルエラーになります。

*Main> sumtimes' [1::Int,2,3] [1::Integer,2,3]

<interactive>:12:25: error:
    • Couldn't match expected type ‘Int’ with actual type ‘Integer’
    • In the expression: 1 :: Integer
      In the second argument of ‘sumtimes'’, namely
        ‘[1 :: Integer, 2, 3]’
      In the expression: sumtimes' [1 :: Int, 2, 3] [1 :: Integer, 2, 3]
*Main>

Num a => [a] -> [a] -> aの2つのパラメータは同じaとなっているので、同じ型でなければなりません。Nun型のインスタンスならなんでもいいわけではありません。

git statusで追加したファイルが表示されない

新規に作成したファイルがgit statusで表示されず、少し焦りました。.gitignoreの指定対象になっていたようです。無理やりgit add``をしたところ、メッセージに教えてもらいました。.gitignore```の設定を修正しました。

$ git add src/DataBase/MySQLX/ExprParser.hs
The following paths are ignored by one of your .gitignore files:
src/DataBase/MySQLX/ExprParser.hs
Use -f if you really want to add them.

MySQLのサンプルデータベースのテーブル定義

いつも忘れるのでメモ

mysql-sql> use world_x;
Query OK, 0 rows affected (0.01 sec)
mysql-sql> show tables;
+-------------------+
| Tables_in_world_x |
+-------------------+
| city              |
| country           |
| countryinfo       |
| countrylanguage   |
+-------------------+
4 rows in set (0.01 sec)
mysql-sql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int(11)  | NO   | PRI | null    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   |     |         |                |
| District    | char(20) | NO   |     |         |                |
| Info        | json     | YES  |     | null    |                |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.09 sec)
mysql-sql> desc country;
+---------+----------+------+-----+---------+-------+
| Field   | Type     | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+-------+
| Code    | char(3)  | NO   | PRI |         |       |
| Name    | char(52) | NO   |     |         |       |
| Capital | int(11)  | YES  |     | null    |       |
| Code2   | char(2)  | NO   |     |         |       |
+---------+----------+------+-----+---------+-------+
4 rows in set (0.01 sec)
mysql-sql> desc countryinfo;
+-------+-------------+------+-----+---------+------------------+
| Field | Type        | Null | Key | Default | Extra            |
+-------+-------------+------+-----+---------+------------------+
| doc   | json        | YES  |     | null    |                  |
| _id   | varchar(32) | NO   | PRI | null    | STORED GENERATED |
+-------+-------------+------+-----+---------+------------------+
2 rows in set (0.01 sec)
mysql-sql> desc countrylanguage;
+-------------+---------------+------+-----+---------+-------+
| Field       | Type          | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| CountryCode | char(3)       | NO   | PRI |         |       |
| Language    | char(30)      | NO   | PRI |         |       |
| IsOfficial  | enum('T','F') | NO   |     | F       |       |
| Percentage  | float(4,1)    | NO   |     | 0.0     |       |
+-------------+---------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
mysql-sql>

Haskellのソースコードの言語拡張をいい感じにフォーマットする

Haskellのコードの先頭に書くやつで、左側の({-#)は揃ってるけど右側(#-})を揃える

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE RecordWildCards #-}

vimtabularいれて、下記コマンド

:'<,'>Tabularize /#-}