9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LisperのためのHy (hylang)

Last updated at Posted at 2022-01-22

他のLisp系言語をそれなりに知っている人がHyについて簡単に知るためのメモ。随時更新。

変更履歴

  • 2024-11-10 Hy 1.0.0対応。旧版の仕様の記述は削除

Overview

  • シンタックスはClojureに近い。ただしプログラミングスタイルはPythonに近い
    • ClojureやSchemeと同様に変数と関数で名前空間が分かれていない(Lisp-1)
    • Common LispやClojureに近いスタイルのマクロが使える(いわゆる伝統的マクロ)
  • Pythonを呼び出したり、逆にPythonから呼び出すこともでき、Hyのコードから対応するPythonのコードを生成することもできる
  • 1.0に向けて破壊的変更が激しくなっている。より生のPythonに近いシンタックスに寄せてきている印象
    • 一時期1.0のalpha版ということで1.0a4といったバージョンになっていたがそれ以降は0.24.0に戻された。
    • 2024/09/22に1.0.0がリリースされた。今後は仕様が安定することが期待される

変数

変数の導入、設定にはsetvを使う。
setvは値を返さないので、設定した値を返すsetxもある。これはPythonのセイウチ演算子(:=)に展開される。

(setv x 10)
;; => None

(setx x 10)
;; => 10

let

局所変数を導入するためにはletが使える。
スタイルとしてはClojureのletに近く、局所変数と値のペアが括弧で括られずフラットに並ぶ。個人的には変数と値の対応が分かりにくくなるので苦手だが、Clojureと同様に,を入れて見やすくすることもできる。
ClojureのletやCommon Lispのlet*と同じで、1つのletの中で前に設定した変数をその後の変数の初期化に利用できる。

Pythonに変換したとき、ユニークな名前の変数に代入しているだけのようである。そのためレキシカルスコープは作らない。

(let [x 10
      y (+ x 20)]
  (print x y))

;; 変換後のPythonコード
; _hy_let_x_2 = 10
; _hy_let_y_3 = _hy_let_x_2 + 20
; print(_hy_let_x_2, _hy_let_y_3)

関数

関数適用

他のLispと同様、関数名をリストの最初に置くと関数適用となる。
リストの2要素目以降(引数)が左から右へ順に評価されていき、全ての値が出揃った時点でリスト先頭の関数が適用される(正格評価)。

(+ 1 2 3) ; => 6

Common Lispとは違い、関数と変数で名前空間が分かれておらず、1つの名前空間を共有している。Scheme、Clojure、Pythonと同じだ。
そのため、値として渡ってきた関数を適用するときもfuncallなどは不要で、単純にリストの先頭に置くだけである。
以下は関数を返す関数を定義し、返された関数を5に適用している例。

(defn add-n-generator [n]
  (fn [x] (+ x n)))

((add-n-generator 10) 5) ; => 15

#* , #** リーダーマクロ

多くのLispには、引数として関数とリストを受け取り、リストを展開して与えられた関数に適用させるためにapplyが用意されている。
Hyではapplyの代わりに#*リーダーマクロを使う。リストの前に#*をつけることがでそのリストが展開される。

(+ #*'(1 2 3)) ; => 6
(+ #*[1 2 3])  ; => 6

;; #*を並べて書くこともできる
(+ #*[1 2 3] #*[4 5]) ; => 15

リーダーマクロ #* をシンボルやタプルの前に付けるときはスペースが必要なことに注意。

(setv lst [1 2 3])

(+ #* lst) ; => 6

;; タプルの前にもスペースが必要
(+ #* #(1 2 3)) ; => 6

同様に、辞書型のデータを展開して関数にキーワード引数として与えることもできる。それには #** を使う。

(defn keyword-arg-func [#** kwargs]
  (print "kwargs: " kwargs))

(keyword-arg-func :key1 1 :key2 2)
; kwargs:  {'key1': 1, 'key2': 2}

(keyword-arg-func #**{"key1" 1, "key2" 2})
; kwargs:  {'key1': 1, 'key2': 2}

;; リストと同様、辞書型を変数に格納してキーワード引数に渡すときは #** の後にスペースが必要
(setv dict1 {"key1" 1, "key2" 2})
(keyword-arg-func #** dict1)

関数定義

関数定義はほぼClojureと同じだが、docstringの位置が異なり、引数リストの後に持ってくる必要がある。なおdocstringはオプショナルである。
例えば、階乗の定義は以下のようになる。他のLisp系言語と同様に、明示的にreturnは必要なく、最後に評価される式が返される。

(defn fact [n]
  "docstring for fact"
  (if (= n 0)
      1
      (* n (fact (- n 1)))))

引数オプション

可変長引数

例えば+のように、可変長引数を取る関数を定義するときには、関数定義の仮引数の前に #* を置く。
例えば以下の例では、argsが可変長引数のリストになる。#*にシンボルが続く場合には間にスペースが必要なことに注意する。

(defn my-plus [#* args]
  (+ #* args))

(my-plus 1 2 3) ; => 6

オプショナル引数

オプショナルな引数を持つ関数を定義するには、引数リストの中で[optional-parameter default-value]のようにパラメータ名とデフォルト値のペアを指定する。
これはオプショナル引数とキーワード引数の複合のような指定の仕方になっており、このoptional-parameterの部分が仮引数、兼キーワード指定子になっている。
オプショナル引数は明示的にキーワードを指定して呼び出すことも、指定しないで呼び出すこともできる。

(defn opt-arg-func [arg1 [key1 12] [key2 34]]
  [arg1 key1 key2])

(opt-arg-func "foo")                   ; ["foo" 12 34]
(opt-arg-func "foo" :key1 21)          ; ["foo" 21 34]
(opt-arg-func "foo" :key2 43)          ; ["foo" 12 43]
(opt-arg-func "foo" :key1 21 :key2 43) ; ["foo" 21 43]
(opt-arg-func "foo" 21 43)             ; ["foo" 21 43]

デフォルト値は必須。オプショナル引数の位置でデフォルト値を指定しないと構文エラーになる。

(defn opt-arg-func2 [[key1 12] [key2 34] key3]
  [key1 key2 key3])
;; =>hy.errors.HySyntaxError: non-default argument follows default argument

任意形式のキーワード引数

仮引数の前に #** を付けることで、形式を定めずにキーワード引数として受け付け、関数内からは辞書型として参照できる。

(defn kwargs-test [#** kwargs]
  kwargs)

(kwargs-test :key1 "val1" :key2 "val2")
;; => {"key1" "val1"  "key2" "val2"}

ここまで出てきた引数オプションは組み合わせて使うこともできる。
以下は必須引数、オプショナル引数を取りつつ、さらに多くの可変長引数と追加のキーワード引数を受け取る関数の例である。

(defn f [required1 required2
         [optional1 None] [optional2 "foo"]
         #* rest #** kwargs]
  (print (.format "required1: {0}, required2: {1}, optional1: {2}, optional2: {3}, rest: {4}, kwargs: {5}"
                  required1 required2 optional1 optional2 rest kwargs)))

(f 1 2 3 4 5 6 7 8 :nine 9 :ten 10)
;; required1: 1, required2: 2, optional1: 3, optional2: 4, rest: (5, 6, 7, 8), kwargs: {'nine': 9, 'ten': 10}

(setv lst [5 6 7 8])
(f 1 2 3 4 #* lst)
;; required1: 1, required2: 2, optional1: 3, optional2: 4, rest: (5, 6, 7, 8), kwargs: {}

(setv dic {"nine" 9, "ten" 10})
(f 1 2 3 4 #* lst #** dic)
;; required1: 1, required2: 2, optional1: 3, optional2: 4, rest: (5, 6, 7, 8), kwargs: {'nine': 9, 'ten': 10}

無名関数

無名関数を作るにはlambdaではなく、ClojureやArcと同様にfnを使う。
本体部分が1つの式を返すだけであればPythonのlambdaに変換されるが、複数の式から構成されている場合は_hy_anon_var_XXなどの名前付き関数に変換される。これらは変換後の関数名を知っていれば呼び出せてしまうので注意が必要である。

;; 本体部分が1つの式のとき
(fn [x] (+ x 1)) ; => <function <lambda> at 0x7fbd9062e8b0>

;; 式の最初の要素に置いて引数を与えれば適用できる
((fn [x] (+ x 1)) 10) ; => 11

;; 本体部分に複数の式が含まれている場合
(fn [x] (print x) (+ x 1))

; # Python変換後
; def _hy_anon_var_5(x):
;     print(x)
;     return x + 1
; _hy_anon_var_5

Hyでは関数と変数の名前空間が分かれていないので、次のように無名関数を変数に代入することでも関数を定義できる。

(setv add
      (fn [x y]
        (+ x y)))

(add 2 3) ; => 5

ドキュメント検索

helpで関数のdocstringを参照できる。

(help fact)

; fact(n)
;     docstring for fact

Common Lispのaproposでは、現在の処理系にロードされているパッケージを横断してドキュメントを検索できた。これに相当するようなものとしては pydoc がある。
これはCommon Lispのaproposとは違って、現在ロードされているものではなく、インストールされているパッケージ全体を検索する。そのため若干時間がかかることに注意が必要。

(import pydoc)
(pydoc.apropos "multiply")

; scipy.sparse.linalg._expm_multiply - Compute the action of the matrix exponential.
; scipy.sparse.linalg.tests.test_expm_multiply - Test functions for the sparse.linalg._expm_multiply module.

高階関数

HyではLispやPythonと同様に、関数がファーストクラスオブジェクトである。そのため、関数を関数に渡したり、値として返すことができる。
map, filter はPython組込みのものが使える、reduceはPythonの標準ライブラリのfunctoolsの中にある。
これらが返してくるシーケンスはmapクラスやfilterクラスのオブジェクトなので、list関数などで利用する型に明示的に変換する必要がある。

mapの例

(defn add1 [n]
  (print f"add1(n = {n})")
  (add n 1))

(setv seq [1 2 3])

(list (map add1 seq)) ; => [2 3 4]

;; 出力:
;; add1(n = 1)
;; add1(n = 2)
;; add1(n = 3)

遅延評価を使いたい場合は、サードパーティライブラリのtoolzなどを使用する。

(import toolz [take])

(list (take 2 (map add1 seq))) ; => [2 3]

;; takeは必要な要素しか評価しない
;; add1(n = 1)
;; add1(n = 2)

filterの例

(defn even? [n]
  (= (% n 2) 0))

(list (filter even? seq)) ; => [2]

reduceの例

(import functools [reduce])

(defn add [a b]
  (+ a b))

(reduce add seq 0) ; => 6

他にitertoolsなども使える。例えば、reduceの溜め込みの途中経過をリストとして取得したければaccumulateが使える。

(import itertools [accumulate])

(list (accumulate (range 1 11) add)) ; => [1 3 6 10 15 21 28 36 45 55]

制御構造

ブロック

do

doは処理をブロックにまとめる構文で、内部の式を順次評価していき、最後の式の値をdoブロック全体の値として返す。レキシカルスコープは作らない。
Clojureのdo, Common Lispのprogn, Schemeのbeginに相当する。

(do (print "foo")
    (print "bar")
    10)
; foo
; bar
; => 10

letも暗黙的にdoのようなブロックを作る。これらは後述するifcondの中でも使う。

条件分岐

if

ifは他のLispとほぼ同じだが、真理値の扱いはPythonと同じ癖があり、色々なものが偽となりうるので注意が必要。

次のものが全て偽として扱われる。

  • False
  • None
  • 零: 0, 0.0
  • 空リスト:[]
  • 空tuple:#()
  • 空dict:{}
  • 空のHyリスト:'()
  • 空文字: ""
(if (or False None 0 0.0 [] #() {} '() "")
    "This is true"
    "This is false")

; => "This is false"

他のLispと異なり、ifは偽の式が必須であることに注意。3引数でないとは構文エラーになる。
条件が真の場合のみ評価したい場合はwhenを使う。whenは条件に合わないときはNoneを返す。

(if True "This is true")
; hy.errors.HySyntaxError: parse error for pattern macro 'if': got unexpected end of macro call, expected: form

(when True "This is true")

cond

condよりifより柔軟な条件分岐構文である。
HyのcondはClojureのcondと同じく、条件部と本体部のペアを並べたものを列挙する方式だ。
本体部で複数の式を並べたいときは明示的にdoを入れる必要があることに注意。
以下の例ではデフォルト節の条件部は:elseとしているが、真になるものであれば何でもいい。

(defn fib [n]
  (cond (= n 0) 0
        (= n 1) 1
        :else (+ (fib (- n 1))
                 (fib (- n 2)))))

(list (map fib (range 1 11))) ; => [1 1 2 3 5 8 13 21 34 55]

when / unless

whenifdoの組合せで、条件部が真(偽)のときに本体部分を順に評価していき最後の式の値を返す。

(when True
  (print "one")
  (print "two")
  3)
; one
; two
; => 3

unlesswhenの条件部を反転させたもので、多くのLispに存在するマクロである。Hyの場合はHyruleという標準ライブラリパッケージに入っている。

(require hyrule [unless])

(unless False
  (print "one")
  (print "two")
  3)
; one
; two
; => 3

繰り返し

シーケンスに対する繰り返し: for

(for [x ["a" "b" "c"]]
  (print x))

; a
; b
; c

(for [x (range 0 10)]
  (print x))

;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
;; 6
;; 7
;; 8
;; 9

2つのループ変数を並べると二重ループになる。これならばforを二重にする方が意図が明確になる分まだいい気がする。

(for [i [1 2 3]
      j [3 2 1]]
  (print (.format "i: {0}, j: {1}" i j)))

; i: 1, j: 3
; i: 1, j: 2
; i: 1, j: 1
; i: 2, j: 3
; i: 2, j: 2
; i: 2, j: 1
; i: 3, j: 3
; i: 3, j: 2
; i: 3, j: 1

(for [i [1 2 3]]
  (for [j [3 2 1]]
    (print (.format "i: {0}, j: {1}" i j))))

Common Lispのloopマクロのforのように複数のシーケンスを並行して舐めていくには、zip を使うなどして複数のシーケンスの各要素のペアからなる1つのシーケンスとしてforを回す。
forのループ変数にも分配束縛のような書き方ができる。

(for [[i j] (zip [1 2 3] [3 2 1])]
  (print (.format "i: {0}, j: {1}" i j)))

; i: 1, j: 3
; i: 2, j: 2
; i: 3, j: 1

loop / recurマクロ

Pythonは末尾再帰最適化を行なわないので、普通に再帰呼び出しを行うとコールスタックを消費する。末尾再帰呼び出しを単なるループとして処理するために、Clojureのloop/recur構文と同じものがHyにも用意されている。
再帰呼び出しの関数名がrecurに固定されていると考えると、Schemeのnamed-letにも似ている。
これはHyの標準ユーティリティ集であるhyruleに含まれている。マクロなのでrequireでロードする必要がある。

以下の例はフィボナッチ数の定義を末尾再帰版に直したものである。

(require hyrule [loop])

(defn fast-fib [n]
  (loop [[cnt 0]
         [pre 1]
         [prepre 0]]
    (if (= cnt n)
        pre
        (recur (+ cnt 1)
               (+ pre prepre) pre))))

(fast-fib 100) ; => 354224848179261915075

リスト内包表記: lfor

繰り返しの結果をリストで取得したいときはPythonのリスト内包表記に展開されるlforを使う。
なおmapでも同じことはできる。

(lfor i (range 1 11) (fast-fib i))
;; => [1 1 2 3 5 8 13 21 34 55]

(list (map fast-fib (range 1 11)))
;; => [1 1 2 3 5 8 13 21 34 55]

例外処理

例外処理にはtry構文が使える。
Common Lispのhandler-caseのようなものだと思ってよい。
本体部分には複数の式を書くことができ、exceptに指定したエラーを捕捉したときの処理を書ける。

(try
  ;; 本体部分
  (print "Start try body")
  (/ 1 0)
  (except [e ZeroDivisionError]
    ;; 例外をeに束縛して処理する
    (print f"Caught an error: {e}")
    e))

;; Start try body
;; Caught an error: division by zero
;; => ZeroDivisionError('division by zero')

except節は複数個並べることもできる。else節は例外が発生しなかったときに実行される。finally節は成否に関わらず通過する。

(try
  (/ 2 0)
  (except [e ZeroDivisionError]
    (print "Division by zero"))
  (except [e TypeError]
    (print "Type Error"))
  (else
    (print "No errors"))
  (finally
    (print "Guaranteed to pass through here")))

;; Division by zero
;; Guaranteed to pass through here

データ構造

リスト

Pythonのリスト。
要素へのアクセスにはgetを使う。(get list1 0)list1[0]のようにPythonの [] リテラルに展開されるので、dictやtupleについても同じように使えることが分かる。

(type [1 2 3])
;; => <class 'list'>

(setv list1 [1 2 3])
(get list1 0)
;; => 1

getに複数の引数を渡すと入れ子になっているリストなどから値を取り出せる。

(setv mat [[1 2 3]
           [4 5 6]
           [7 8 9]])

(get mat 2 2) ; => 9
(get (get mat 2) 2) ; => 9

リストの特定の要素に代入するには setv と getを組み合わせる。

(setv (get list1 0) 10)
;; Python: list1[0] = 10

list1
;; => [10 2 3]

スライス

スライスは最大3引数の cut に対応する。
https://qiita.com/yossyyossy/items/0c8dc2ed53466d970fe4

(let [from 1
      to None
      by 2]
  (cut [1 2 3 4 5] from to by)) ; => [2, 4]

(cut [1 2 3 4 5] 2 None) ; => [3, 4, 5]
(cut [1 2 3 4 5] 0 2) ; => [1, 2]
(cut [1 2 3 4 5] 2 4) ; => [3, 4]
(cut [1 2 3 4 5] -4 -2) ; => [2, 3]

タプル

イミュータブルなリスト。
#(1 2 3) のようなリテラルで表記する。tuple関数によって作れる。
イミュータブルなので要素に値を代入しようとするとエラーになる。

(type #(1 2 3)
;; => <class 'tuple'>

(tuple [1 2 3])
;; => #(1 2 3)

(setv tuple1 #(1 2 3))
(setv (get tuple1 0) 10)
;; TypeError: 'tuple' object does not support item assignment

set (集合型)

集合型。順序を持たず、要素の重複を許さない。

(type #{1 2 3})
;; <class 'set'>

(dir #{1 2 3})
; [... "add" "clear" "copy" "difference" "difference_update" "discard" "intersection" "intersection_update" "isdisjoint" "issubset" "issuperset" "pop" "remove" "symmetric_difference" "symmetric_difference_update" "union" "update"]

(set [1 2 3])
;; #{1 2 3}

(setv sets #{"a" "b" "c" "d"})
(print sets)
;; {'c', 'd', 'b', 'a'}

(sets.add "e")
(print sets)
;; {'c', 'e', 'b', 'a', 'd'}

(sets.remove "a")
(print sets)
;; {'c', 'e', 'b', 'd'}

(sets.pop)
;; => "c"
(print sets)
;; {'e', 'b', 'd'}

要素が集合に属するかどうかは in 演算子を使う。

(in 1 #{1 2 3}) ; => True

集合演算

;; 包含関係 (<, <=, >, >=)
(<= #{1 2} #{1 2 3}) ; => True
(<= #{1 2 3} #{1 2}) ; => False

;; 同値
(= #{1 2} #{1 2}) ; => True

(setv sets2 #{1 2 3})

;; 積集合
(sets2.intersection #{3 4 5}) ; => #{3}

;; 和集合
(sets2.union #{3 4 5}) ; => #{1 2 3 4 5}

;; 差集合
(sets2.difference #{3 4 5}) ; => #{1 2}
(- sets2 #{3 4 5}) ; => #{1 2}

dict (辞書型)

属性リスト的な使い方で、keyとvalueを交互に並べる。
参照にはリストと同じで get を使い、 setv と組み合わせて代入できる。これは assoc でも同じことができる。

(setv d {"dog" "bark" "cat" "meow"})
(type {"dog" "bark" "cat" "meow"}) ; <type 'dict'>

(d.get "dog") ; => "bark"
(get d "dog") ; => "bark"

(setv (get d "dog") "wan"
      (get d "cat") "nyan")
d ; => {"dog" "wan"  "cat" "nyan"}

(require hyrule [assoc]) ;; Hy 1.0a4 からHyruleに分離され、requireが必要になった
(assoc d "dog" "bark") ; => None
d ; => {"dog" "bark"  "cat" "nyan"}

;; 辞書型に対するループ

(for [[k v] (d.items)]
  (setv formtxt "key: {0}, value: {1}")
  (print (formtxt.format k v)))

;; key: dog, value: bark
;; key: cat, value: nyan

前述の通り、関数のキーワード引数に展開して与えることもできる。

(defn say [[dog "bark"] [cat "meow"]]
  (print "Dog say" dog)
  (print "Cat say" cat))

(say #** d)

;; Dog say bark
;; Cat say nyan

クラス

TODO

式 (Expression)

見た目上は他のLispのリストに近く、クォートで評価から保護しない限り評価規則に従ってプログラムとして評価される。
Hyのコードはこのデータ型から成り立っており、マクロの操作対象のデータとなる。
Pythonのリストとは別のデータ構造として定義されており、データとしてリストが欲しい時は主にPythonのリストの方を使う。

;; リテラル
(type '(1 2 3))
;; => <class 'hy.models.Expression'>

;; コンストラクタ
(hy.models.Expression [1 2 3])
;; => '(1 2 3)

タプルを継承しており、+で結合したりgetで要素を取得することもできる。

(+ '(1 2 3) '(4 5 6))
;; => '(1 2 3 4 5 6)

(get '(1 2 3) 1)
;; => '2

マクロ

マクロ定義はCommon Lispに近い。いわゆる伝統的マクロで、defmacroを使って定義する。

例1: my-when

例えば、whenを自前で定義してみると、以下のようになる。

(defmacro my-when [predicate #* body]
  `(if ~predicate
       (do ~@body)
       None))

式の前に準クォート(バッククォート)を付けると、通常のクォートと同じように式を評価から保護できるが、式の一部分だけを評価して評価結果を埋め込むことができる。
アンクォートは~、リストを展開するためのスプライシングアンクォートは~@で、ここはClojureと同じだ。

マクロの展開にはhy.macroexpand-1が使える。

(hy.macroexpand-1 '(my-when True
                     (print "This is True")))

; (if True
;     (do (print "This is True"))
;     None)

例2: lexical-let

letlambdaのシンタックスシュガーでしかないので、自分で定義することもできる。
Hy標準のletはレキシカル環境を作らないが、以下のように定義すると、レキシカル版のletを作ることができる。

(defmacro lexical-let [var-pairs #* body]
  (setv var-names (lfor x var-pairs (get x 0))
        var-vals  (lfor x var-pairs (get x 1)))
  `((fn [~@var-names] ~@body) ~@var-vals))

(hy.macroexpand-1 '(lexical-let [[one 1]
                                 [two 2]
                                 [three 3]]
                     (print one two three)))

; => '((fn [one two three] (print one two three)) 1 2 3)
(macroexpand-1
  '(let* [one 1
          two (+ one one)
          [three four] [(+ one two) (+ two two)]] ; 展開形を見ると分配束縛もできることが分かる
     (print one two three four)))

;; '((fn []
;;     (setv one 1
;;           two (+ one one)
;;           [three four] [(+ one two) (+ two two)])
;;     (print one two three four)))

例: gensym, with-gensymsを使うケース

TODO

TODO: defmacro!を使う例

リーダーマクロ

TODO

モジュール

TODO

importrequire

importrequireについては後述するが、マクロを利用するためにはhy.contrib.walkモジュールからletマクロをrequireする必要がある。

(require [hy.contrib.walk [let]])
(let [x 1
      y (+ x 1)]
  (print (.format "x: {0}, y: {1}" x y)))
; x: 1, y: 2

外部ライブラリ

Numpy

(import numpy :as np)

(setv arr (np.array [[1 2 3]
                     [4 5 6]
                     [7 8 9]]))
arr.flags
;; C_CONTIGUOUS : True
;; F_CONTIGUOUS : False
;; OWNDATA : True
;; WRITEABLE : True
;; ALIGNED : True
;; WRITEBACKIFCOPY : False
;; UPDATEIFCOPY : False

arr.ndim ; => 2
arr.size ; => 9
arr.dtype ; => dtype('int64')

;; スカラー倍
(* arr 3)
;; array([[ 3,  6,  9],
;;        [12, 15, 18],
;;        [21, 24, 27]])

;; アダマール積(要素積)
(* arr arr)
;; array([[ 1,  4,  9],
;;        [16, 25, 36],
;;        [49, 64, 81]])

;; 行列積
(np.dot arr arr)
;; array([[ 30,  36,  42],
;;        [ 66,  81,  96],
;;        [102, 126, 150]])

;; 一様乱数で100x100行列を作って行列積を取る
(import numpy.random :as rand)

(setv bigarr1 (rand.rand 1000 1000))
(setv bigarr2 (rand.rand 1000 1000))

(np.dot bigarr1 bigarr2)

;; array([[ 28.38096367,  28.63420504,  28.01482173, ...,  27.26330009,
;;          25.56717227,  27.39401733],
;;        [ 25.26386499,  23.78039895,  22.81641922, ...,  24.37012314,
;;          22.31017675,  22.20606049],
;;        [ 24.79624411,  23.11758526,  24.45533016, ...,  24.47093385,
;;          22.3951194 ,  24.02735416],
;;        ..., 
;;        [ 25.65465691,  25.7403632 ,  23.54518075, ...,  24.36247407,
;;          21.92434498,  23.04834359],
;;        [ 22.37135022,  21.32717967,  21.92101116, ...,  20.93922527,
;;          20.07961519,  20.54109093],
;;        [ 27.50945536,  25.99902791,  25.73058543, ...,  25.71283456,
;;          23.86456424,  25.27311888]])
9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?