2016-06-26 8 views
7

私はHaskellの不変変数の概念とかなり混同しています。 Haskellの変数の値を変更することはできないようです。私はGHCiの中に次のコードしようとしたときの変数の値が変更を行ったように。しかし、それが見えた:Haskellの不変変数とは何ですか?

Prelude> foo x=x+1 
Prelude> a=1 
Prelude> a 
1 
Prelude> foo a 
2 
Prelude> a=2 
Prelude> a 
2 
Prelude> foo a 
3 

は不変変数の考え方と、この競合をしていますか?

多くの感謝!

+1

私の周りではうまくいきません。 – Netwave

+0

'a = 1; '.hs'ファイルの中で' a = 2'を実行し、 'ghc'を使ってコンパイルします... – Bakuriu

+8

GHCiコマンドはIOアクションなので、入力したものが' do'ブロックの中にある場合と似ています。つまり、同じ名前への後続の代入は、ネストされた 'let'sのようなものであり、あなたは古いバインディングです。 – Bakuriu

答えて

18

Haskellでは、既存の変数を変更することはできません。しかし、変数名を再利用することができます。これはすべてここで起こっています。

Prelude> let a = 1 
Prelude> :i a 
a :: Num a => a  -- Defined at <interactive>:2:5 
Prelude> let a = 2 
Prelude> :i a 
a :: Num a => a  -- Defined at <interactive>:4:5 

これらは実際には同じ名前を呼ばれるように起こる2全体の別々の、異なる変数、以下のとおりです。これを見るための一つの方法は、変数が宣言されました:i[nfo]ディレクティブを使用して、GHCiのを依頼することです!あなただけaを求める場合は、これを確認する1つの方法を新しい定義が“が”を優先されますが、古いものはまだそこ–で、コメントでカイで述べとして、関数内でaを使用することです:

Prelude> let a = 2 
Prelude> :i a 
a :: Num a => a  -- Defined at <interactive>:4:5 
Prelude> let f x = a + x 
Prelude> let a = 3 
Prelude> f (-2) 
0 

faとも呼ばれる新しい変数を定義したことに気にする必要はありません。その視点から、aは常にそのままの1つの不変変数でした。


なぜGHCiが後の定義を好むのかについて少し話をする価値があります。これは、ではなく、がハスケルコードで起こることはありません。あなたは、以下のモジュールをコンパイルしようとした場合、特に、それは単に重複定義に関するエラーを与える:

a = 1 
a = 2 

main :: IO() 
main = print a 

このようなものは、GHCiの中で許可されていることを理由に、それはHaskellのモジュールは異なる動作することです。 GHCiコマンドのシーケンスは、事実上、IOモナドアクションのシーケンスを形成します。&dagger;;プログラムは

main :: IO() 
main = do 
    let a = 1 
    let a = 2 
    print a 

でなければならないであろう。すなわち、あなたがモナドについて学んできた場合、あなたはこれが

main = 
    let a = 1 in (let a = 2 in (print a)) 

のためだけの構文糖であり、これは本当に、なぜにとって極めて重要ビットであることを知っていますよaという名前をもう一度使用することができます。第2のものは、a = 2です。が狭い範囲にあります。が最初のものより長くなります。したがって、よりローカルであり、ローカル定義が優先されます。これが良い考えかどうかは議論の余地があります。それはあなたが

greet :: String -> IO() 
greet name = putStrLn $ "Hello, "++name++"!" 

のような機能を持たせることができる、それはあなたが“再定義をできることを実際にはかなり便利です、ほかに誰か他の場所で

name :: Car -> String 
name car | rollsOverAtRightTurn car = "Reliant Robin" 
     | fuelConsumption car > 50*litrePer100km 
             = "Hummer" 
     | ...      = ... 

定義するという理由だけで、それは動作を停止しないことであるために良いの引数”変数はGHCiで欺かれていますが、ではありません。これは、一貫した動作を示すはずの適切なプログラムで再定義するような良い考えです。


; dfeuerの発言として、これは完全な真実ではありません。 IO do-blockで許可されていないGHCiでいくつかのことを行うことができます。特に、dataのタイプとclassを定義できます。しかし、通常のステートメントや変数定義は、モナドのIOと同じように動作します。あなたが実際に見ることができるように

+0

欠けているもの:GHCiは 'data'、' newtype'、 'type'、' class'、 'instance'宣言を許します。これらはHaskellの' do'構文では許されません。 – dfeuer

+1

GHCiが*インタラクティブ*環境であることを考えると、それは不可欠な機能です。定義を間違って入力した回数は何回ですか?毎回完全に新しい名前を選択する必要がある場合、 'myFunction'の前の定義にエラーが含まれている' myFunction7'のような読めない名前で簡単に終わるでしょう。正しい定義を使用して... – Bakuriu

+0

右。それが必要な場合は、完全に異なるワークフローを適用する必要があります。明示的なスコープが設定されている可能性があります。 – leftaroundabout

0

(GHCiのを使用して、他の答えは...結構ですが、それはGHCiのかモナドに固有のものではない明確にするために)その次Haskellのプログラム

main = 
    let x = 1 in 
    let f y = x + y in 
    let x = 2 in 
    print (x * f 3) 

10ではなく8を出力しますが、変数はHaskellでのみ「バインド」でき、「変異」することはできません。言い換えれば、プログラムは上記と同じです(と呼ばれるα-同等のみバインド変数の名前の一貫した変更を意味し、;詳細はhttps://wiki.haskell.org/Alpha_conversionを参照)、それは明らかである

main = 
    let x1 = 1 in 
    let f y = x1 + y in 
    let x2 = 2 in 
    print (x2 + f 3) 

ことx1x2は異なる変数です。

関連する問題