読者です 読者をやめる 読者になる 読者になる

【Haskell】Stringの連結でハマった

Haskell

ここ数日、「すごいHaskell楽しく学ぼう!」でHaskellしてます。関数型プログラミングを勉強してみたかった。

第4章を少し進めて再帰の考え方がわかってきたため、復習としてFizzBuzzを。

fizzbuzz :: Int -> [String]
fizzbuzz n | n < 1 = []
fizzbuzz n = fizzbuzz (n-1) ++ [(fb n)]
    where fb n
            | n `mod` 15 == 0 = "FizzBuzz"
            | n `mod` 3 == 0 = "Fizz"
            | n `mod` 5 == 0 = "Buzz"
            | otherwise = show n

Intを引数にとり、1から引数で指定した数までをFizzBuzzします。

引数nを関数fbでFizzBuzz文字へ変換し、その先頭へ再帰でまたFizzBuzz文字をつなげています。

本題ですが、3行目のリストの連結で2時間ほどハマっていました。

リストの連結には2つ方法がある

リストの連結には2つの方法があります。 : を使う方法と ++ を使う方法です。

Prelude> let x = [3,5,7]
Prelude> x ++ [5, 3]
[3,5,7,5,3]

Prelude> 5 : x
[5,3,5,7]
Prelude> 7 : 5 : x
[7,5,3,5,7]
Prelude>

これだけでは違いがわかりにくいですね。

これではどうでしょう。

Prelude> [5,3] ++ x
[5,3,3,5,7]
Prelude> x : 5

<interactive>:31:1: error:
    • Non type-variable argument in the constraint: Num [[t]]
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall t. (Num [[t]], Num t) => [[t]]
Prelude> x : 5 : 3

<interactive>:32:1: error:
    • Non type-variable argument in the constraint: Num [[t]]
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall t. (Num [[t]], Num [t], Num t) => [[t]]
Prelude>

++演算子は2つの値を入れ替えても動作します。

一方 : 演算子はエラーが発生しました。

演算子の定義を確認してみましょう。

Prelude> :t (++)
(++) :: [a] -> [a] -> [a]

Prelude> :t (:)
(:) :: a -> [a] -> [a]

つまり、

  • ++演算子は「2つのリストを連結する」
  • : 演算子は「後者のリストの先頭に前者を追加する」

というように考えられます。似ているようで似てなかった。

FizzBuzz書いているときは当該の行を

fizzbuzz n = (fizzbuzz (n-1)) : (fb n)

としておりました。エラーメッセージでも型の齟齬が吐かれていましたが、少しややこしいものでした。

キョウリョクナカタスイロン

先程の一行を型に注目するとこうなります。

fizzbuzz n = [String] : String

またエラーメッセージではこの行について

  • 「(fizzbuzz (n-1))の返り値の型、[[String] ]になってんぞ。[String]じゃね?」

  • 「(fb n)の返り値の型、[Char]になってんぞ。[[String] ]じゃね?」

と、強力な型推論のおかげ(せい)で余計に惑わされました。

以上です。

まとめ

haskellを触り始めて1日目、エラーにハマったおかげでかえって満足です。エラーメッセージとがっつり対峙できたため今後はスルスルと進めていきたいですね。カモン、デバッグりょく

【Retrofit2】jsonschema2pojoがUnexpected character was〜する

pojo変換用のclassをjsonschema2pojoにレスポンスをコピペして作るわけですが、ぼくの環境だとどうも

There's a problem: Unexpected character ('m' (code 109)): was expecting double-quote to start field name (line 2, column 2)

f:id:shimbaroid:20160818234319p:plain

とエラーが出てしまいます。フィールドにあたる文字のクォーテーションが無いぞとのことです。

これは、GoogleChromeのJSONViewという拡張機能が原因でした。

この拡張機能jsonのレスポンスを整形してchrome上で見やすくしてくれるものですが、フィールドにあたる文字のクォーテーションを外してしまいます。そのために上記のエラーが発生していました。

じゃあコピペのあとにキーひとつずつにクォーテーションをつければいいわけですが、ぼくはこのときだけSafariを使っています。生のjsonならpojo classを生成できます。

ありがとうございました。

【Android Studio】Api keyを始めとしたgit管理したくない定数を環境変数で管理する

Api keyやGoogle AnalyticsのトラッキングIDなんかは、ハードコーディングしてgithub等でオープンにするのが好ましくないですよね。

そこでOS X環境変数にそれらを登録しておき、Android Studioのビルドの際に参照するようにして回避しましょう。

OS X環境変数にkeyを登録する

ターミナルから以下を実行します。

$ launchctl setenv APIKEY hogehoge

APIKEYがkey、hogehogeがvalueにあたるKeyValue形式です。

build.gradleから環境変数を参照する

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        // 環境変数を参照する
        manifestPlaceholders = [api_key: System.getenv("APIKEY")]
    }
}

環境変数のAPIKEYを参照し、api_keyへ格納しています。

AndroidManifest.xmlからmanifestPlaceholdersを参照する

<application>
    <meta-data android:name="apiKey" android:value="${api_key}"/>
</application>

javaプログラムの中からAndroidManifest.xmlのmeta-dataを参照する

String key = "";
try{
    ApplicationInfo info
            = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
    key = info.metaData.getString("apiKey");
}catch(PackageManager.NameNotFoundException e){
    e.printStackTrace();
}

// keyを使った処理〜〜

これでString keyはhogehogeになっています。

Windowsから環境変数を登録し参照することは検証していないです。

ありがとうございました。

参考

AndroidManifest.xmlにAPIキーを書いたコードをGitHubにコミットしないために AndroidManifest.xmlに記述したメタデータを取得する

【Jenkins】Ubuntu16.04にjenkinsをインストールする

多くがQiitaや他の技術ブログのコピペになってしまいますが、Ubuntu16.04にセットアップした話は見かけなかったのでここに残します。

JDKのインストール

$sudo add-apt-repository ppa:webupd8team/java
$sudo apt-get update
$sudo apt-get install oracle-java7-installer

Jenkinsのインストール

$wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
$sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
$sudo apt-get update
$sudo apt-get install jenkins

nginxのインストール

$sudo apt-get install nginx

nginxのリバースプロキシの設定

$gedit /etc/nginx/sites/available/default

で設定ファイルを開き、以下のように編集。(保存ができない場合、下記参照)

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    # Make site accessible from http://localhost/
    server_name localhost;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        if (!-f $request_filename) {
            proxy_pass http://localhost:8080;
            break;
        }
    }
}

※保存ができない場合、以下のコマンドで権限を変更してから再度編集。

$sudo chmod a+w /etc/nginx/sites-available/default


nginxを再起動

$sudo service nginx restart

これでブラウザから http://localhost/にアクセスするとjenkinsが起動していることが確認できます。 f:id:shimbaroid:20160624164949p:plain

初回はパスワードを求められます。赤字でハイライトされているpathのinitialAdminPasswordのなかに記述されています。これを確認します。

initialAdminPasswordを確認する

$sudo chmod a+r+x /var/lib/jenkins/secrets
$sudo chmod a+r+x /var/lib/jenkins/secrets/initialAdminPassword
$cat /var/lib/jenkins/secrets/initialAdminPassword


これで表示された英数字列を先ほどのブラウザ画面にコピペしてContinueを押します。 f:id:shimbaroid:20160624171121p:plain

pluginのインストールですが、Install suggested pluginsで問題ないかと思います。

インストール完了!

f:id:shimbaroid:20160624171520p:plain

Jenkinsのインストールが完了しました。今回は以上です。

参考

UbuntuにJenkinsをインストールする

【Android】EspressoでUIテストの準備

Android

build.gradleに以下を追記

// defaultConfig 
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

// dependencies
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2' 
androidTestCompile 'com.android.support:support-annotations:23.2.1'

support-annotationの一行は適宜バージョンを変更する。gradleのエラーにでるバージョンに指定すれば問題ない。

 

テストクラス(e.g. MainActivityTest.java)頭に@RunWith()を追記

@RunWith(AndroidJUnit4.class)
public class MainActivityTest extends ActivityInstrumentationTestCase2{
.
.
.

あとはテストを書いていく。

【Cloud 9】インサートモードから抜けられない?

Cloud 9

Cloud9のkeyboard modeをvimにしましたが、インサートモードから抜けられず困りました。

もしchromeを使っていて、さらにvimiumをインストールしている場合、エスケープの入力がすべてそちらにいっている可能性があります。

f:id:shimbaroid:20160606163355p:plain

vimiumのoptionからcloud9を弾くよう設定しましょう。

【Android Studio】ライブラリがFailed to resolve ...で更新できない

ここ最近、いくつかAndroid向けにライブラリをつくってはbintray、jcenterを使って公開しています。

 

しかしライブラリの更新をjcenterの方に登録してから、自身のアプリでdependenciesの書き換えをおこないgradle syncをするとFailed to resolve ...とのエラーがでて更新できません。

f:id:shimbaroid:20160603214550p:plain

 

調べたところ、jcenter repositoryのurlを変更してやるとうまくいくよう。

 

stackoverflow.com

 

デフォルトでは https://jcenter.bintray.com/ となっているところを、

projectのbuild.gradleを書き換え http://jcenter.bintray.com/とします。

f:id:shimbaroid:20160603215352p:plain

allprojects -> repositoriesを書き換えました。これでうまくいきました。