見出し画像

【Haskell】基本文法【言語習得への道】


https://www.jdoodle.com/

コメント

プログラミングでは、コード中にコメントを書くことができます。
Haskellでは文頭に「--」を書くことで、コメントとして扱われます。
コメント扱いされた文は実行されることはありません。

-- この行はコメントです.
-- putStrLn "コメントです"

main :: IO ()
main = do
    putStrLn "Hello, World"
    putStrLn "Not, Comment"

-- 実行結果
-- Hello, World
-- Not, Comment

変数

Haskellで変数をつける時は、左に変数名・右に数値や文字列を置き、間に「=」を挟みます。変数と関数は名前を小文字で始める必要があります。 大文字で始めるとエラーになります。

また,Haskellの変数では、値を代入は基本は一度しかできないと思う。(たぶん間違っている)

型宣言と代入を同時

-- データ型と初期値を同時
String text = "text"
String text2 = "Text"

main :: IO ()
main = do
    -- 出力
    putStrLn text
    putStrLn text2

    -- エラー出た
    -- text2 = "TEXT"
    -- putStrLn text2

-- 実行結果
-- text
-- Text

型宣言と代入が別

-- データ型→初期値
text :: String
text = "text"

text2 :: String
text2 = "Text"

main :: IO ()
main = do
    -- 出力
    putStrLn text
    putStrLn text2

    -- エラー出た
    -- text2 = "TEXT"
    -- putStrLn text2

-- 実行結果
-- text
-- Text

局所的な変数や関数

let式は、局所的な変数や関数を定義するために使われます。let式はinキーワードと組み合わせて使われ、定義された変数や関数はinの後の式で使用できます。

-- let式の例
calculateArea :: Float -> Float
calculateArea radius =
    let area = pi * square radius
        square x = x * x
    in area

main :: IO ()
main = do
    let radius = 5.0
    print (calculateArea radius)

また、doブロック内でもletを使って変数を定義できます。この場合、inは不要です。

-- let式の例
main :: IO ()
main = do
    let radius = 5.0
        square x = x * x
    print (pi * square radius)

where句は、関数定義の後に局所的な変数や関数を定義するために使われます。where句で定義された変数や関数は、その関数全体で使用できます。

-- where句の例
calculateArea :: Float -> Float
calculateArea radius = area
  where
    area = pi * square radius
    square x = x * x

main :: IO ()
main = do
    let radius = 5.0
    print (calculateArea radius)

letとwhereの使いどこ

let~in句は変数が先に宣言され、中身の関数は後ろに回されます。 しかし、関数の中身こそが中心に来るべきであり、最初にメインの関数を表示し、内部で使用している変数を補助的に表示するほうが可読性が上がります。

https://minegishirei.hatenablog.com/entry/2024/01/14/152609
sphere r = 
    let pi = 3.1415 
    in 
        4/3 * pi * r * r * r

main = do
    print(sphere(10)) 
-- 4188.666666666666 
sphere r = 4/3 * pi * r * r * r
    where
        pi = 3.1415

main = do
    print(sphere(10))
-- 4188.666666666666 

長い変数名

変数名が長い時に、_か大文字で区切ります。

-- _で繋ぐ
text_text :: String
text_text = "text"

-- -で繋ぐ
-- エラー
-- text-Text :: String
-- text-Text = "Text"

-- 小文字→大文字で繋ぐ
textText :: String
textText = "Text"

-- 大文字で繋ぐ
textTextUpper :: String
textTextUpper = "TEXT"

-- 出力
main :: IO ()
main = do
    putStrLn text_text
    -- putStrLn text-Text
    putStrLn textText
    putStrLn textTextUpper

-- 実行結果
-- text
-- Text
-- TEXT

関数

string00 :: IO ()
string00 = do
    let text = "text"
    let _text = "Text"
    putStrLn text
    putStrLn _text

    let helloworldmessage = "Hello, World"
    let hello_world_message = "Hello, World"
    putStrLn helloworldmessage
    putStrLn hello_world_message

main :: IO ()
main = string00

-- 実行結果
-- text
-- Text
-- Hello, World
-- Hello, World

型宣言

string00 :: IO ()
  • string00関数の型を宣言しています。

  • IO ()は、この関数がIOアクションであり、副作用を持つことを示しています。返り値の型は()(ユニット型)です。

関数本体

string00 = do
    let text = "text"
    let _text = "Text"
    putStrLn text
    putStrLn _text

    let helloworldmessage = "Hello, World"
    let hello_world_message = "Hello, World"
    putStrLn helloworldmessage
    putStrLn hello_world_message
  • doブロック内で一連のIOアクションを定義しています。

  • letを使って変数を定義します。Haskellでは変数は不変(イミュータブル)です。

  • putStrLnは文字列をコンソールに出力するIOアクションです。

メイン関数

main :: IO ()
main = string00
  • main関数もIOアクションであり、プログラムのエントリーポイントです。

  • main関数内でstring00を呼び出しています。

文字列

基本文法

-- 初期設定
import System.IO

-- 文字列
helloWorld :: String -> String
helloWorld str1 = "Hello World"

-- 実行
main :: IO ()
main = do
    let echoStr = helloWorld "mass"
    putStrLn echoStr
    -- Hello World

    -- 文字列連結
    let helloWorld2 str1 = "Hello World" ++ str1
    let echoStr2 = helloWorld2 "mass"
    putStrLn echoStr2
    -- Hello Worldmass

    -- 改行
    let helloWorld3 str1 = "Hello World\n" ++ str1
    let echoStr3 = helloWorld3 "mass"
    putStrLn echoStr3
    -- Hello World
    -- mass

コードの解説

このHaskellコードは、NimのコードをHaskellに変換したものです。それぞれの関数と実行部分について説明します。

-- 初期設定
import System.IO

`System.IO`モジュールをインポートしています。これは標準入力や標準出力を扱うために必要です。

-- 文字列
helloWorld :: String -> String
helloWorld str1 = "Hello World"

`helloWorld`関数は、引数として文字列を受け取り、常に "Hello World" を返します。Nimの `HelloWorld` 関数に相当します。

-- 実行
main :: IO ()
main = do
    let echoStr = helloWorld "mass"
    putStrLn echoStr
    -- Hello World

`main`関数はHaskellプログラムのエントリーポイントです。`helloWorld`関数を呼び出し、その結果を `echoStr` に代入し、`putStrLn`で標準出力に出力します。

    -- 文字列連結
    let helloWorld2 str1 = "Hello World" ++ str1
    let echoStr2 = helloWorld2 "mass"
    putStrLn echoStr2
    -- Hello Worldmass

`helloWorld2`関数は、引数として受け取った文字列を "Hello World" に連結して返します。Nimの `HelloWorld2` 関数に相当します。`++`はHaskellの文字列連結演算子です。

    -- 改行
    let helloWorld3 str1 = "Hello World\n" ++ str1
    let echoStr3 = helloWorld3 "mass"
    putStrLn echoStr3
    -- Hello World
    -- mass

`helloWorld3`関数は、引数として受け取った文字列を "Hello World\n" に連結して返します。Nimの `HelloWorld3` 関数に相当します。`\n`は改行文字です。

全体として、`main`関数内で3つの異なる関数を呼び出し、それぞれの結果を標準出力に出力しています。

整数を文字列に変換

import Text.Printf (printf)

main :: IO ()
main = do
    let i = 5 :: Int
    let a = show i -- 文字列へ変換
    putStrLn $ "5以下:" ++ a -- 文字列の結合
    putStrLn $ "5以下:" ++ show i
    printf "5以下:%d" i

解説

import Text.Printf (printf)

`printf`関数をインポートしています。`printf`はC言語の`printf`と同様にフォーマットされた文字列を出力するために使用されます。

main :: IO ()
main = do:

`main`関数の型を定義しています。`main`はHaskellプログラムのエントリーポイントで、`IO`アクションを返します。
`do`ブロックを使って複数のIOアクションを順に実行します。

let i = 5 :: Int

変数`i`を定義し、整数`5`を代入しています。`:: Int`は型注釈で、`i`が`Int`型であることを明示しています。

let a = show i

変数`a`を定義し、`i`を文字列に変換して代入しています。`show`関数は任意の型を文字列に変換します。

putStrLn $ "5以下:" ++ a

`putStrLn`関数を使って、文字列を標準出力に出力します。`"5以下:" ++ a`は文字列の結合を行っています。

putStrLn $ "5以下:" ++ show i

同様に、`i`を`show`関数で文字列に変換し、結合して出力しています。

printf "5以下:%d" i

`printf`関数を使って、フォーマットされた文字列を出力します。`%d`は整数をフォーマットするためのプレースホルダで、`i`の値がここに挿入されます。

このコードは、整数`5`を文字列に変換して結合し、異なる方法で出力する例を示しています。

数値

基本的な算術演算と文字列の出力を行います

main :: IO ()
main = do
    print 42
    print (42 + 21) -- 足し算
    print (42 - 21) -- 引き算
    print (42 * 2) -- かけ算
    print (42 / 21) -- 割り算
    putStrLn "42 + 21" -- 文字列

-- 実行結果
-- 42
-- 63
-- 21
-- 84
-- 2.0
-- 42 + 21

main関数の定義

main :: IO ()

`main`関数はHaskellプログラムのエントリーポイントです。`IO ()`はこの関数が入出力操作を行い、副作用を持つことを示しています。

入出力操作の開始

main = do

`do`ブロックを使って、複数の入出力操作を順番に実行します。

数値の出力

print 42

`print`関数を使って、数値`42`を標準出力に表示します。

足し算の結果を出力

print (42 + 21) -- 足し算

`42 + 21`の計算結果を`print`関数で表示します。

引き算の結果を出力

print (42 - 21) -- 引き算

`42 - 21`の計算結果を`print`関数で表示します。

かけ算の結果を出力

print (42 * 2) -- かけ算

`42 * 2`の計算結果を`print`関数で表示します。

割り算の結果を出力

print (42 / 21) -- 割り算

`42 / 21`の計算結果を`print`関数で表示します。

文字列の出力

putStrLn "42 + 21" -- 文字列

`putStrLn`関数を使って、文字列`"42 + 21"`を標準出力に表示します。

リスト型

配列の操作を行います。

import Data.List (intercalate)

main :: IO ()
main = do
    let ary = ["a", "b", "c", "d", "e", "f"]
    putStrLn $ show ary ++ ", " ++ show (length ary)
    putStrLn $ ary !! 0
    putStrLn $ ary !! 5
    putStrLn $ ary !! (length ary - 1)

    let results = [ary !! 0, ary !! 2]
    putStrLn $ show results
    
-- ["a","b","c","d","e","f"], 6
-- a
-- f
-- f
-- ["a","c"]

モジュールのインポート

import Data.List (intercalate)

`intercalate`関数を使用するために`Data.List`モジュールをインポートしています。

main関数の定義

main :: IO ()
main = do

`main`関数はHaskellプログラムのエントリーポイントです。`IO ()`はこの関数が入出力操作を行い、副作用を持つことを示しています。

配列の初期化

    let ary = ["a", "b", "c", "d", "e", "f"]

`let`を使って、文字列のリスト`ary`を初期化します。

配列とその長さを出力

    putStrLn $ show ary ++ ", " ++ show (length ary)

`putStrLn`関数を使って、`ary`リストとその長さを表示します。`show`関数はリストを文字列に変換します。

配列の特定の要素を出力

    putStrLn $ ary !! 0
    putStrLn $ ary !! 5
    putStrLn $ ary !! (length ary - 1)

`putStrLn`関数を使って、`ary`リストの特定の要素を表示します。`!!`演算子はリストの指定されたインデックスの要素を取得します。

新しい配列 results を作成し、特定の要素をコピー

    let results = [ary !! 0, ary !! 2]

`let`を使って、`ary`リストの特定の要素をコピーして新しいリスト`results`を作成します。

results 配列を出力

    putStrLn $ show results

`putStrLn`関数を使って、`results`リストを表示します。`show`関数はリストを文字列に変換します。

ループ文

数値と配列を使ったループの例を示しています。

main :: IO ()
main = do
    -- 数字のfor文
    putStrLn "数字のループ文"
    mapM_ print [0..6]

    let ary = ["a", "b", "c", "d", "e", "f"]
    putStrLn $ "リスト: " ++ show ary
    putStrLn $ "リストのループ文: " ++ show (length ary)

    putStrLn "リストのループ文"
    mapM_ putStrLn ary
    
-- 数字のループ文
-- 0
-- 1
-- 2
-- 3
-- 4
-- 5
-- 6
-- リスト: ["a","b","c","d","e","f"]
-- リストのループ文: 6
-- リストのループ文
-- a
-- b
-- c
-- d
-- e
-- f

main関数の定義

main :: IO ()
main = do

`main`関数はHaskellプログラムのエントリーポイントです。`IO ()`はこの関数が入出力操作を行い、副作用を持つことを示しています。

数字のループ文

    putStrLn "数字のfor文"
    mapM_ print [0..6]

`putStrLn`関数を使って、"数字のループ文"という文字列を表示します。`mapM_`関数を使って、0から6までの数字を順に`print`関数で表示します。

配列の初期化

    let ary = ["a", "b", "c", "d", "e", "f"]

`let`を使って、文字列のリスト`ary`を初期化します。

リストの出力

    putStrLn $ "リスト: " ++ show ary
    putStrLn $ "リストのループ文: " ++ show (length ary)

`putStrLn`関数を使って、`ary`リストとその長さを表示します。`show`関数はリストを文字列に変換します。

リストのfor文

    putStrLn "リストのループ文"
    mapM_ putStrLn ary

`putStrLn`関数を使って、"リストのループ文"という文字列を表示します。`mapM_`関数を使って、`ary`リストの各要素を順に`putStrLn`関数で表示します。

条件文

以下のコードは、0から10までの数値をループし、それぞれの数値が5以下かどうかを判定して出力するものです。

import Control.Monad (when)

main :: IO ()
main = do
    -- 0から10までの範囲でループを実行
    mapM_ (\i -> when (i <= 5) $ do
        print (i <= 5)  -- 条件が真であることを表示
        putStrLn $ "5以下:" ++ show i) [0..10]

    -- 0から10までの範囲で再度ループを実行
    mapM_ (\i -> when (not (i <= 5)) $ do
        print (i <= 5)  -- 条件が偽であることを表示
        putStrLn $ "5以上:" ++ show i) [0..10]
        
-- True
-- 5以下:0
-- True
-- 5以下:1
-- True
-- 5以下:2
-- True
-- 5以下:3
-- True
-- 5以下:4
-- True
-- 5以下:5
-- False
-- 5以上:6
-- False
-- 5以上:7
-- False
-- 5以上:8
-- False
-- 5以上:9
-- False
-- 5以上:10

モジュールのインポート

import Control.Monad (when)

`when`関数を使用するために`Control.Monad`モジュールをインポートしています。

main関数の定義

main :: IO ()
main = do

`main`関数はHaskellプログラムのエントリーポイントです。`IO ()`はこの関数が入出力操作を行い、副作用を持つことを示しています。

0から10までの範囲でループを実行

    mapM_ (\i -> when (i <= 5) $ do
        print (i <= 5)  -- 条件が真であることを表示
        putStrLn $ "5以下:" ++ show i) [0..10]

`mapM_`関数を使って、0から10までの範囲でループを実行します。`when`関数を使って、`i`が5以下の場合に条件が真であることを表示し、"5以下:"と`i`の値を表示します。

0から10までの範囲で再度ループを実行

    mapM_ (\i -> when (not (i <= 5)) $ do
        print (i <= 5)  -- 条件が偽であることを表示
        putStrLn $ "5以上:" ++ show i) [0..10]

`mapM_`関数を使って、0から10までの範囲で再度ループを実行します。`when`関数を使って、`i`が5以下でない場合に条件が偽であることを表示し、"5以上:"と`i`の値を表示します。




いいなと思ったら応援しよう!