北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

msys2の最新版で [lost server] が発生

msys2 をアップデートしたら、 tmuxクリップボード周りを操作すると [lost server] 的なメッセージが出て死ぬようになってしまった。今までも何度かあったこととは言え、辛さに溢れる。

とりあえずこれの通り msys2 のランタイムのバージョン下げたら直った。この辺もいつもの通りの対処法。

https://github.com/Alexpux/MSYS2-packages/issues/791#issuecomment-275253779

MSYS2でHDBC-sqlite3をコンパイル

当然のことながら、msys2のshellではなくmingw64のshellから操作する。

まず、 sqlite3 を入れる。

pacman -S mingw64/mingw-w64-x86_64-sqlite3

後はビルドするだけなんだけど、2点注意がいる。

  • --extra-include-dirs--extra-lib-dirs にmingw64関連のディレクトリを明示する
  • --skip-msys を指定する

--skip-msysここ とか ここ 読めばわかるけど、指定しなければwin環境のGHCがデフォルトで内部に持ってるmsys2のPATHを見てしまうのを、抑制して見ないようにしてくれる。

stack build --skip-msys --extra-include-dirs=/c/msys64/mingw64/include/  --extra-lib-dirs=/c/msys64/mingw64/lib/ HDBC-sqlite3

余談

--extra-* の指定が必要な理由はよくわからない。明示しなくてもmingw64のshellを使ってるのだから勝手に見て欲しいもの。

依存ライブラリのチェックはcabal側でやってて 、ここで使うgccがどれなのかがまず重要である。ここに関しては一応 stack 側で --with-gcc=/c/msys64/mingw64/bin/gcc のような指定は可能で、これを指定するとライブラリのチェックでは落ちなくなる。しかし、結局buildの部分で落ちる。

2017-01-29 10:45:52.197846: [debug] Run process: C:\stack_root\setup-exe-cache\x86_64-windows\Cabal-simple_mPHDZzAJ_1.24.2.0_ghc-8.0.1.exe --builddir=.stack-work\dist\ca59d0ab build --ghc-options " -ddump-hi -ddump-to-file"
@(System\Process\Read.hs:340:3)

--  While building package HDBC-sqlite3-2.3.3.1 using:
      C:\stack_root\setup-exe-cache\x86_64-windows\Cabal-simple_mPHDZzAJ_1.24.2.0_ghc-8.0.1.exe --builddir=.stack-work\dist\ca59d0ab build --ghc-options " -ddump-hi -ddump-to-file"
    Process exited with code: ExitFailure 1

...略...

    [7 of 7] Compiling Database.HDBC.Sqlite3 ( Database\HDBC\Sqlite3.hs, .stack-work\dist\ca59d0ab\build\Database\HDBC\Sqlite3.o )

    C:\tools\msys64\tmp\stack12828\HDBC-sqlite3-2.3.3.1\hdbc-sqlite3-helper.c:1:21: error:
         fatal error: sqlite3.h: No such file or directory
    compilation terminated.
    `gcc.exe' failed in phase `C Compiler'. (Exit code: 1)

ここで setup.exe 呼ぶのにも --with-gcc が必要な気がするのだけど、 stack がそれを指定していないように見える。が、面倒なのでこれ以上は追いかけてない。

AllowAmbiguousTypes拡張と型適用

このように f を定義して実行したい。

f :: String -> String
f = show . read

main :: IO ()
main = putStrLn $ f "True"

エラーが出る。

Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:5:5: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘show’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 16 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘(.)’, namely ‘show’
      In the expression: show . read
      In an equation for ‘f’: f = show . read

test.hs:5:12: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘read’
      prevents the constraint ‘(Read a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Read Ordering -- Defined in ‘GHC.Read’
        instance Read Integer -- Defined in ‘GHC.Read’
        instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
        ...plus 22 others
        ...plus 7 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘(.)’, namely ‘read’
      In the expression: show . read
      In an equation for ‘f’: f = show . read
Failed, modules loaded: none.

showread の対象とする型 a0 がきちんと決まってないのが原因なので、これを f に対して指定できるようにする。

f :: (Show a, Read a) => String -> String
f = (show :: a -> String) . read

再びエラーとなる。

Prelude> :r
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:4:6: error:
    • Could not deduce (Read a0)
      from the context: (Show a, Read a)
        bound by the type signature for:
                   f :: (Show a, Read a) => String -> String
        at test.hs:4:6-41
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘f’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature:
        f :: (Show a, Read a) => String -> String
Failed, modules loaded: none.

aShowReadインスタンスだと言ってる割には、型の本文に a が登場しないのでこれを決定する方法がない。 AllowAmbiguousTypes を使うとこのチェックを遅らせられるよと教えてくれているので、有効にする。 が、これまたゴツいエラー。

Prelude> :r
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:5:6: error:
    • Could not deduce (Show a2) arising from a use of ‘show’
      from the context: (Show a, Read a)
        bound by the type signature for:
                   f :: (Show a, Read a) => String -> String
        at test.hs:4:1-41
      Possible fix:
        add (Show a2) to the context of
          an expression type signature:
            a2 -> String
    • In the first argument of ‘(.)’, namely ‘(show :: a -> String)’
      In the expression: (show :: a -> String) . read
      In an equation for ‘f’: f = (show :: a -> String) . read

test.hs:5:29: error:
    • Could not deduce (Read a0) arising from a use of ‘read’
      from the context: (Show a, Read a)
        bound by the type signature for:
                   f :: (Show a, Read a) => String -> String
        at test.hs:4:1-41
      The type variable ‘a0’ is ambiguous
      These potential instances exist:
        instance Read Ordering -- Defined in ‘GHC.Read’
        instance Read Integer -- Defined in ‘GHC.Read’
        instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
        ...plus 22 others
        ...plus 7 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘(.)’, namely ‘read’
      In the expression: (show :: a -> String) . read
      In an equation for ‘f’: f = (show :: a -> String) . read
Failed, modules loaded: none.

これは show :: a -> String が暗黙的に show :: forall a. a -> String と解釈されているのが原因なので、 ScopedTypeVariables 拡張を使う。

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a. (Show a, Read a) => String -> String
f = (show :: a -> String) . read

main :: IO ()
main = putStrLn $ f "True"

f の定義についてのエラーはなくなった。後は呼び出し側。

*Main> :r
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:8:19: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘f’
      prevents the constraint ‘(Read a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Read Ordering -- Defined in ‘GHC.Read’
        instance Read Integer -- Defined in ‘GHC.Read’
        instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
        ...plus 22 others
        ...plus 7 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘($)’, namely ‘f "True"’
      In the expression: putStrLn $ f "True"
      In an equation for ‘main’: main = putStrLn $ f "True"
Failed, modules loaded: none.

a を指定すればいいのだから、ここで TypeApplications の登場。

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

f :: forall a. (Show a, Read a) => String -> String
f = (show :: a -> String) . read

main :: IO ()
main = putStrLn $ f @Bool "True"
Prelude> :r
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> :main
True

めでたしめでたし。せっかく TypeApplications を使うなら、 f の定義ももう少し簡潔になる。

f :: forall a. (Show a, Read a) => String -> String
f = show @a . read

余談1. AllowAmbiguousTypes の妥当性

型変数作って TypeApplications 使って適用したいだけなのに突然 AllowAmbiguousTypes 拡張が出てきてなんだよって思ったかもしれないが、 論文中ではこいつの必要性は書いてあって、そもそもは TypeApplications を有効にすると自動的に有効になるようになってた。

このへんのメールのやり取り でない方がいいだろって話になって、 このコミットで消された。

余談2. Proxy

TypeApplications を使えるコンパイラを持っていないあなたでも、型の役割をする式である Proxy 型を使うことができるのだ! 副作用で型の本文に a が入るようになるので、 AllowAmbiguousTypes 拡張も不要になる。

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Proxy

f :: forall proxy a. (Show a, Read a) => proxy a -> String -> String
f _ = (show :: a -> String) . read

main :: IO ()
main = putStrLn $ f (Proxy :: Proxy Bool) "True"

だが、勘がいいあなたなら気がついてしまったかもしれない。 Proxy は可読性をあげてくれるだけで、なくても困らないことを。

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall proxy a. (Show a, Read a) => proxy a -> String -> String
f _ = (show :: a -> String) . read

main :: IO ()
main = putStrLn $ f [False] "True"

余談3. Type defaulting in GHCi

GHCiのデフォルト型の割り当ては強力 なので、なんと f がそのままコンパイルできてしまうのだ!! ただし、勝手に () になってしまう。

*Main> f = show . read
*Main> f "()"
"()"
*Main> f "True"
"*** Exception: Prelude.read: no parse

ConnectionFailure getAddrInfo: does not exist (Name or service not known) が出た

vagrantubuntu/zesty64 を使ったら、 https://github.com/commercialhaskell/stack/issues/2536 的なメッセージが出てかなりの高確率で stack setup に失敗した。

そもそも安定版使ってないほうが悪かったので、 ubuntu/xenial64 使うようにしたら収まった。とは言え、その直前に zesty64 も senial64 もどちらのboxもアップデートされた(20170119.1.0)っぽいので、何が悪かったかは切り分けてない。

2017年センター試験英語

最近ひどく疲れているので http://www.toshin.com/center/ から英語を解いた。リスニングが42点で筆記が169点。おもったよりひどくないと思ってしまったけど、本来満点取らないと駄目なやつだよね、これ。現役の頃を思い出して気分転換にはなったので良しとする。こうやって明確に解法も解答も決まっているのは頭の準備体操にはいいね。

stackのコードを読む(3)

  • リソルバのダウンロード先URLのデフォルトは Stack.Config.Urls で定義されているがコンフィグで上書きできる
  • リゾルバはYAMLでこんな感じで全パッケージとバージョンが書かれてる
packages:
  drawille:
    .. 省略 ..
    version: '0.1.2.0'
    .. 省略 ..
    description:
      cabal-version: '1.10'
      modules:
      - System.Drawille
      provided-exes:
      - image2term
      - senoid
      packages:
        base:
          components:
          - library
          - test-suite
          range: ==4.*
        hspec:
          components:
          - test-suite
          range: ! '>=1.11 && <2.4'
        containers:
          components:
          - library
          - test-suite
          range: ==0.5.*
        QuickCheck:
          components:
          - test-suite
          range: ! '>=2.6'
      tools: {}
  shakespeare:
  .. 省略 ..

ghci 7.10 と 8.0 のレコード記法の違い

DuplicateRecordFields を実装した影響だと思うけど、 ghci で重複するレコード名を定義したときの振る舞いが 7.10 と 8.0 で違ってる。

まず 7.10 。「フィールド定義が消される」という振る舞いに見える。

$ stack --resolver ghc-7.10 ghci
Configuring GHCi with the following packages:
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> data X = X { x :: Bool }
Prelude> data Y = Y { x :: Int }
Prelude> let anX = X { x = True }

<interactive>:18:11:
    Constructor ‘X’ does not have field ‘x’
    In the expression: X {x = True}
    In an equation for ‘anX’: anX = X {x = True}
Prelude> let anX = X { x = 10 }

<interactive>:19:11:
    Constructor ‘X’ does not have field ‘x’
    In the expression: X {x = 10}
    In an equation for ‘anX’: anX = X {x = 10}
Prelude> :t anX

<interactive>:1:1:
    Not in scope: ‘anX’
    Perhaps you meant one of these:
      ‘and’ (imported from Prelude), ‘any’ (imported from Prelude)

8.0 で同じことをやってみる。フィールドがないことを検知してないように思える。気持ち悪いのは、 True を渡すと値を生成できてしまうこと。しかも True はなかったことにされて x フィールドの値を評価すると例外が投げられる。

$ stack ghci
Configuring GHCi with the following packages:
GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from C:\tools\msys64\tmp\ghci1668\ghci-script
Prelude> data X = X { x :: Bool }
Prelude> data Y = Y { x :: Int }
Prelude> let anX = X { x = True }

<interactive>:67:11: warning: [-Wmissing-fields]
    • Fields of ‘X’ not initialised: x
    • In the expression: X {x = True}
      In an equation for ‘anX’: anX = X {x = True}
Prelude> let anX = X { x = 10 }

<interactive>:68:19: error:
    • No instance for (Num Bool) arising from the literal ‘10’
    • In the ‘x’ field of a record
      In the expression: X {x = 10}
      In an equation for ‘anX’: anX = X {x = 10}
Prelude> :t anX
anX :: X
Prelude> let (X x') = anX in x'
*** Exception: <interactive>:3:11-24: Missing field in record construction x

これが起こるのは REPL 上だけで、ソースコード上でフィールド名が重複していれば当然コンパイルが通らないので、大きな問題ではないだろう。そもそも 7.10 系の振る舞いが理想的かってのもある。バグな気はするけど。