ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

HaskellコミュのHaskell初心者

  • mixiチェック
  • このエントリーをはてなブックマークに追加
Haskell初心者です
本をよみながら知ったこと、気づいたこと、妄想など
メモ書き的に書いていきたいです。
詳しい方は突っ込みをいれていただければ

ちなみにGraham HuttonのProgramming Haskellをよんでます

コメント(47)

タプル
PythonではDictionaryのkeyにもなるタプル
Haskellでもなにかいいことがあるのだろうか。
要素数は最大64個

let a = (1,2,3)

0番目の要素はfst,
1番目の要素はsndで取得できる
http://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%97%E3%83%AB

n番目の要素は自分で定義しないといけない
let get5th (_,_,_,_,a,_) = a
let b = (1,3,4,5,7,5)
get5th b
7

http://stackoverflow.com/questions/15558278/how-to-get-nth-element-from-a-10-tuple-in-haskell
リストの型はすべておなじ、タプルは型が異なってよい
6の命名規則で 「_」で始まってもいけない
「_」 単体はワイルドカードを意味する

引数としてなにがきてもOK、値は無視して評価されない的な
3のリスト操作に追記

・unshift的な
b:a
1:[2,3,4]
ラムダ式

\ をλと読む

(\x->x+x) 2

javascriptで書けば
(function (x) { return x+x })(2)
リスト内包表記
記述が一番数学っぽい

数学:
{x^2 | x ∈ {1..3}}
Haskell
[x^2 | x <- [1..3]]

where句と組み合わせる場合はこんな感じ
let a = [(x^2,y) | x <- [1..z], y<-[1..w]] where { z = 3; w = 4 }

内包表記では生成器を「,」で区切るが、where句では「;」で区切る
リスト内包表記(2)

二次元配列の場合
生成器の中のxsは暗示的に型定義もされるのがさすが

let flatten xss = [x|xs <- xss, x<-xs]
flatten [[1,2],[3]]
[1,2,3]
本書の正誤表はこちら
http://www.mew.org/~kazu/doc/book/haskell-typo3.html
リスト内包表記3
かなり実感がわいてきた
findKeyの第2引数がkvPairsはリストで全て型がそろっているので
(key', val) <- kvPairsみたいな荒技(のようにみえることが)できる

let findKey key kvPairs = [val|(key', val)<- kvPairs, key==key']
findKey 'b' [('a',1),('b',2),('a',3),('b',4)]
[2,4]
再帰関数

関数定義の章に記載のあった(n+k)パターンは訳注の予言通り
現在では使用不可になっていた
<interactive>:39:9: Parse error in pattern: n + 1

http://stackoverflow.com/questions/3748592/what-are-nk-patterns-and-why-are-they-banned-from-haskell-2010

数学的帰納法的には便利そうですが、、
再帰関数の6.1章でもばっちりかいてあったがbannされたようだ。

つづいての6.2章のリストに対する再帰も
let pd [] = 1
let pd (n:rest) = n * pd rest
pd [1,3,4]
*** Exception: <interactive>:44:5-29: Non-exhaustive patterns in function pd
とおこられる
そういえば1.5章のHaskellの妙味のsumの定義も再帰関数だが
これも動かない
let ss [] =0
let ss (x:rest) = x + ss rest
ss [1,3]
*** Exception: <interactive>:41:5-29: Non-exhaustive patterns in function ss

ググるとこれがでてくるが、パターンマッチの網羅が足りない?
http://stackoverflow.com/questions/8435575/non-exhaustive-patterns-in-function
リストに対する再帰は、これを参考に解決しました
http://qiita.com/shuhei/items/be8a0d280197a08f303b

ghciでは関数の型定義をそのままではできない
letを単につけてもできない

結論、onelinerで定義する
関数型定義だけletをつけて、あとの定義は";"でつなぐ
適当に行をわけてもうまくいかない


let pd:: [Int]->Int; pd [] = 1 ; pd (n:rest) = n* pd (rest)
pd [1,3,4]
12


let ss::[Int]->Int; ss [] = 0; ss (x:rest) = x + ss rest;
ss [1,3,5]
9
ghciで全てすませたいというブログ
http://tnomura9.exblog.jp/14672658/

guardもonelinearで記述できる

let ab n | n >= 0 = n | otherwise = -n

ただし-4のような負の数をいれるときに
ab -4
ではなく
ab (-4)
としなければならない

こちらは組み込み関数のabsでも同じだった
ちょっと飛躍するがgoogle spreadsheetには
excelのセル関数にいくつか本質的な関数を追加している
FilterやArrayformulaだ

Filter ( exprByRange , conditionByRange, conditionByRange )
https://support.google.com/docs/answer/3093197
Arrayformula ( exprByRange )
https://support.google.com/docs/answer/3093275

たとえば
google spreadsheet関数の以下のFilterをHaskellで書いてみる

=Filter ( {1,2,3} * {4,5,6} , {1,2,3} >=2 )

[ a * b | (a,b) <- zip [1,2,3] [4,5,6], a >=2 ]
>17
>数学的帰納法的には便利そうですが、、
>再帰関数の6.1章でもばっちりかいてあったがbannされたようだ。

(n+k)がだめんだけで、nだけだとok

let fb::Int->Int; fb 0 = 1; fb 1 = 1; fb n = fb(n-2)+fb(n-1)
fb 3
3
fb 6
13

let ft::Int->Int; ft 0=1; ft n = n * ft (n-1)
ft 3
6
ft 5
120
MathematicaでのSumの記載
Sum[ i^2, { i, 0, 10} ]
https://reference.wolfram.com/language/ref/Sum.html

Wolfram Alphaでも同じ(違う場合が結構有る
http://www.wolframalpha.com/input/?i=Sum%5Bi%5E2%2C%7Bi%2C0%2C10%7D%5D

Haskellで書くと
sum i^2, [ i <- [0..10]]

ただし、MathematicaやWofram Alphaのように変数をかけない
Sum[ i^2, { i, 0, x} ]
>4,5の関数の定義

配列でなくてもタプルでもできる。あれ。

let f (x,y,z) = x^2+y-z
f (4,3,5)
14

ドメイン言語をよんでいると、なにがHaskellの機能で
何がドメイン言語の機能なのかわかりづらい(初心者にとっては)

いまDiagramsというドメイン言語をみているのでやっとリファレンスにたどり着いたところ
http://projects.haskell.org/diagrams/haddock/Diagrams-Util.html

Quick startにちょろっと書かれていてもわかりづらい。。
http://projects.haskell.org/diagrams/doc/quickstart.html
There's actually nothing special about the (#) operator: it's just reverse function application, that is,
> x # f = f x

let (#) :: a -> (a -> b) -> b; (#) = flip ($)

これだけの定義でいいのはすごい

let f x = x^2
2 # f

unixのコマンドみたいにパイプで関数をつないだらおもしろいなあとおもったが
パイプは型宣言などで利用される予約語みたい。残念

method cascadingっぽく .でつなぐのがいいのかも

let (.) :: a -> (a -> b) -> b; (.) = flip ($)
let f x = x^2
2 . f . f

予約語でないascii記号

let (.) :: a -> (a -> b) -> b; (.) = flip ($)
let (#) :: a -> (a -> b) -> b; (#) = flip ($)
let (&) :: a -> (a -> b) -> b; (&) = flip ($)
let (%) :: a -> (a -> b) -> b; (%) = flip ($)
let (?) :: a -> (a -> b) -> b; (?) = flip ($)
let (!) :: a -> (a -> b) -> b; (!) = flip ($)

+,-,*,/も定義できるが標準機能を上書きしてしまう

二文字以上であれば他のascii記号をまぜても大丈夫みたい(例外はあるとおもうが)
let (||) :: a -> (a -> b) -> b; (||) = flip ($)
let (=~) :: a -> (a -> b) -> b; (=~) = flip ($)
let (!~) :: a -> (a -> b) -> b; (!~) = flip ($)
let (.=) :: a -> (a -> b) -> b; (.=) = flip ($)
let (@=) :: a -> (a -> b) -> b; (@=) = flip ($)
>method cascadingっぽく .でつなぐのがいいのかも

これはダメだった。「.」は関数合成演算子だそうだ

let f x = x^2
let g y = (-y)
( f.g) x
16

また
!はForce evaluation
|| は他の言語同様Booleanのoperator

今読んでいるGraham Hutton本は最低限のことが書かれた本なので
こまかいことは書いていないので以下を参照した

http://www.imada.sdu.dk/~rolf/Edu/DM22/F06/haskell-operatorer.pdf
Haskell Operator (他にいい情報源がないものか)

http://rigaux.org/language-study/syntax-across-languages-per-language/Haskell.html

本家のこちらを読んでもよくわからない
https://www.haskell.org/onlinereport/haskell2010/
>今読んでいるGraham Hutton本は最低限のことが書かれた本なので
>こまかいことは書いていないので以下を参照した

7.5の関数合成に書いてあった(付録Bの記号表)をみないときづかなかった
虚数の定義
HaskellではData.Complexが用意されているが、iは定義されていないので
自分で定義する

import Data.Complex
let i = 0.0 :+ 1.0

とすれば
i * i
(-1.0) :+ 0.0

したの例をみると
import Data.Complex
let i = 0 :+ 1

とだけしているが、あたらしいバージョンだと問題ないのか?(手元のバージョンはghc 7.6.3)
別のまじないが作用しているのか。。
http://projects.haskell.org/diagrams/gallery/Quasifuchsian.html

手元のエラー(型違いということなのだろう)
<interactive>:84:2:
No instance for (RealFloat Integer) arising from a use of `*'
Possible fix: add an instance declaration for (RealFloat Integer)
In the expression: i * i
In an equation for `it': it = i * i
:+ は複素数のコンストラクタで定義されている
http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Complex.html

!a :+ !a
しかしこの「!」マークは?(先の表にはForce evaluationとあったが)

またここにも
http://projects.haskell.org/diagrams/gallery/Quasifuchsian.html
> data Moebius = M !C !C !C !C deriving (Eq,Show)

と「!」マークがならぶ

同じ疑問を盛った人がいた
遅延評価しないということですね
http://stackoverflow.com/questions/993112/what-does-the-exclamation-mark-mean-in-a-haskell-declaration
>The third parameter, however, has a ! in front of it, so is strictly evaluated: (4+4) is executed, and 8 is stored in that memory location.
ghciの :コマンド
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci-commands.html

import Data.Complex
let i = 0 :+ 1
type C = Complex Double
としておいて
-------------------
:type i
i :: Complex Integer
-------------------
:info i
i :: Complex Integer -- Defined at <interactive>:14:5
-------------------
:info C
type C = Complex Double -- Defined at <interactive>:19:6
-------------------
:info Complex
data Complex a = !a :+ !a -- Defined in `Data.Complex'
instance Eq a => Eq (Complex a) -- Defined in `Data.Complex'
instance RealFloat a => Floating (Complex a)
-- Defined in `Data.Complex'
instance RealFloat a => Fractional (Complex a)
-- Defined in `Data.Complex'
instance RealFloat a => Num (Complex a)
-- Defined in `Data.Complex'
instance Read a => Read (Complex a) -- Defined in `Data.Complex'
instance Show a => Show (Complex a) -- Defined in `Data.Complex'
-------------------
:kind Complex
Complex :: * -> *
--------------------
:browse Data.Complex
data Complex a = !a :+ !a
cis :: RealFloat a => a -> Complex a
conjugate :: RealFloat a => Complex a -> Complex a
imagPart :: RealFloat a => Complex a -> a
magnitude :: RealFloat a => Complex a -> a
mkPolar :: RealFloat a => a -> a -> Complex a
phase :: RealFloat a => Complex a -> a
polar :: RealFloat a => Complex a -> (a, a)
realPart :: RealFloat a => Complex a -> a

-------
10.2 dataによる型宣言

data Bool = False | True
data A = B | C

新しく定義する型(A)と構成子(B,C)の名前は、Hugs(またはghci)に対して何か特別な意味を盛っている訳ではない
名前には今までに使われなかったという事実以外の意味を持っていない

data A = B | C

:info A
data A = B | C -- Defined at <interactive>:29:6

:info B
data A = B | ... -- Defined at <interactive>:29:10

:info C
data A = ... | C -- Defined at <interactive>:29:14
type C = Complex Double -- Defined at <interactive>:19:6


-----
data Moebius = M !C !C !C !C

この場合は、!CのCは先に定義していないとダメ
MoebiusもMもこの行で定義されている(ということは初心者目には分かりづらい)
予約語な@に出くわした

fixpointAttractive moebius@(M a b c d) = ....
みたいな

といっても:infoとかでは何も出てこない
(. や+や-などの演算子ならでてくる)

ググと、asパターンがでてきた
http://www.sampou.org/haskell/tutorial-j/patterns.html

let f (x:xs) = x:x:xs

の x:xsに名前をつけて簡単にできる
ここではsという名前をつけている

let f s@(x:xs) = x:s
f [1,2,3]
[1,1,2,3]

わりと緩く「@」をつけられる

let f s@(x:t@xs) = x:s ++ t
f [1,2,3]
[1,1,2,3,2,3]
@はなるほど
手続き型言語では代入というざっくりとした行為で
いろんなことをしていることがわかる
組み込みクラス(3.9 基本クラス)

Eq, Show, は代数系を定義しようとしたときには使う可能性がある
Readもあると入出力がでてくるとつかうかも
Ordは代数系による

Enum,Ixというのが使われていたので調べてみる

Enum
Enum クラスは一列にならべられた型の上の演算を定義する
http://www.sampou.org/haskell/report-revised-j/basic.html

Ix インデックス演算
Ix クラスはある型の値の連続した部分範囲を整数の上に写像する のに用いられる
http://www.sampou.org/haskell/report-revised-j/ix.html
$もよくでてくるがこれもシンタックシュガーかな

http://blog.sarabande.jp/post/13660559473

show (1+1)
"2"

putStrLn (show (1+1))
2

putStrLn $ show (1+1)
2

putStrLn $ show $ 1+1
2

putStrLn . show $ 1+1
2

(putStrLn . show) $ 1+1
2
let と where

letはghciで使いますが
inと組み合わせた別の使い型もあり

これが初心者にはよみずらい

http://www.sampou.org/haskell/tutorial-j/patterns.html

let g a b c d = let { y = a*b ; f x = (x+y)/y } in f c + f d
g 1 3 4 5
5.0

in で返す値を書いてて、letでその前提を書いている
{}をつけてくれればよめるかもしれないが
これだけかかれていてもわかりづらい

let y = a*b
f x = (x+y)/y
in f c + f d


この例であればwhereでも書けしwhereの方がわかりやすい
let h a b c d = f c + f d where { y = a*b; f x = (x+y)/y; }
h 1 3 4 5
5.0

whereとletを組み合わせると
こちらはできるが、

let j a b c d = let { f x = (x+y)/y; } in f c + f d where { y = a*b; }
j 1 3 4 5
5.0

逆はできない
let k a b c d = let { y = a*b; } in f c + f d where { f x = (x+y)/y; }

<interactive>:117:64: Not in scope: `y'
<interactive>:117:67: Not in scope: `y'

詳しいことはこちら(よんでない)
https://wiki.haskell.org/Let_vs._Where
Data.Arrayをimportすると小文字のarrayが使えるようになる
小文字なんだ。。(なんか微妙な違和感あり)

import Data.Array

:info array
array :: Ix i => (i, i) -> [(i, e)] -> Array i e
-- Defined in `GHC.Arr'
「!」はdataの宣言時にforce evaluationで利用したが
「!」は配列の時にも利用される
リストの場合の参照が「!!」であるのに似ている

Data.Arrayの利用方法の簡単な説明はこちら
http://www.moon.sannet.ne.jp/okahisa/haskell-sort/array.html

import Data.Array
let a = array (1,3) [(i,i-1)| i <- [1..3]]
a
array (1,3) [(1,0),(2,1),(3,2)]
a! 1
0
a! 2
1
a! 3
2


array (添字の最小値,添字の最大値) 連想リスト
のように
連想リストの添字の最小、最大を最初に決めておく必要があるのがなんか使い方を
うまく限定しているのだろうか

Graham本はだいたいよみおわったことにして
そろそろ実践的なことをしたくなってきた
http://tnomura9.exblog.jp/14966671

まずはコマンドライン引数から


import System.Environment (getArgs)

main = do
args <- getArgs
print args
Importの書き方も気になる

https://wiki.haskell.org/Import

import System.Environment (getArgs)
は、
System.Environmentの getArgsだけを読み込む


import System.Environment
getProgName
"<interactive>"

import System.Environment (getArgs)
getProgName
<interactive>:3:1: Not in scope: `getProgName'


import System.Environment as E (getArgs)
getArgs
[]
E.getArgs
[]

E.getArgsだけでgetArgsはもってこないようにするには
import qualified System.Environment as E (getArgs)
E.getArgs
[]
getArgs
<interactive>:4:1:
Not in scope: `getArgs'
Perhaps you meant `E.getArgs' (imported from System.Environment)

また
>Data.Arrayをimportすると小文字のarrayが使えるようになる
>小文字なんだ。。(なんか微妙な違和感あり)

arrayも関数なのでおかしくはない。
Import Data.Array as Array
としておけば
Array.arrayとして使えばいい
ファイル入出力をしたい

http://labs.timedia.co.jp/2012/12/haskellsvgtutorilalwritefile-tut0svg-writepolygons-blue-100100-prelude-t.html

let str = readFile "test.txt"
:info str
str :: IO String -- Defined at <interactive>:4:5

str <- readFile "test.txt"
:info str
t :: String -- Defined at <interactive>:14:1



ghciでなくファイルにかくときは

% cat test.txt
Test

% cat read.hs
main = do
t <- readFile "test.txt"
putStrLn t

> ghci
:load read.hs
main

"Test"

ここにきてdoというのがでてきた
http://qiita.com/saltheads/items/6025f69ba10267bbe3ee

%cat read2.hs
main = readFile "test.txt" >>= putStrLn

> ghci
:load read2.hs
main

"Test"
あと細かいところ

runghc read.hs
コンパイルしなくていい
毎回コンパイルするとファイルがたくさんできてしまうw

lhsファイル
コメント部分が主で、プログラム部分はすべて"> "で始める
markdownで書くとそのまま公開できる

runghc read.lhs

あとはFayをつかってjsにしたりできるようになれば便利
>あとはFayをつかってjsにしたりできるようになれば便利

js対応は、ブラウザーフレンドリーかGHC互換かで選ぶみたいです
Fay < Haste < GHCJS

Hasteは以下のようにするとnode.jsでも使える
hastec --start=asap test.hs

Diagramsを使おうとするとGHCJSでないとだめみたい
http://chrisdone.com:10001/day/diagrams/today/recent?id=85377

ログインすると、残り9件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Haskell 更新情報

Haskellのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング