Skip to content

Commit

Permalink
🎉 (FSharp/) Add new article.
Browse files Browse the repository at this point in the history
  • Loading branch information
Comamoca committed Feb 18, 2024
1 parent bea2ea4 commit 731744a
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 42 deletions.
184 changes: 184 additions & 0 deletions article/FSharp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# FSharp

3行でまとめると

- Microsortが作った
- .NETで動く
- すごい関数型言語


コンパイラ/インタプリタがdotnetコマンドに組み込まれてるので、nugetを取ってきたりREPL/ビルド/実行へのアクセスがめちゃくちゃやりやすい。
さすがMS。


言語の機能的な側面でいうと、一般的な関数型言語が備えてるものをだいたい備えていて、.NET言語らしくC#との連携もやりやすくなっていたりとMS色が強い。
ただ、MS自体はサポートはしているものの、言語の発展などはコミュニティ任せになっているところが課題らしい。ちょっと残念だけど、言語の機能は良いのにケツモチが弱いせいで普及していない言語は幾度も見たことがあるのでまだマシな扱いかもしれない。


## 開発環境の準備

`dotnet`コマンドを用意する。AURなら[`dotnet-sdk`](https://archlinux.org/packages/?name=dotnet-sdk)がある。

エディタの設定についても軽く書いていく。
自分はVimmer(!=Neovim)なのでVimで整備する方法を紹介していく。

- LSP
vim-lspを導入していると思うので、`LspManageServers`とかからfsharpのLSPサーバーを適当にインストールしていく。
F#ファイルを開くとLSPサーバーをインストールするかダイアログが出てくるので、そこからインストールしてもいい。

- ハイライト
これ周りで検索すると公式のプラグインが出てくるのだけど実はこれ地雷で、ハイライト機能とセットで補完機能が付いてくる(うまく動かない)ので別のを使う。
自分は[DrTom/fsharp-vim](https://github.com/DrTom/fsharp-vim)を使わせて頂いている。若干不安なハイライティングをしてくるけど致し方ない。

Neovimの場合はMasonが対応していると思う(未確認)ので、それをインストールして`TSInstall`すれば行けると思う。(未確認)
Emacsは[emacs-fsharp-mode](https://github.com/fsharp/emacs-fsharp-mode)があるので、Elgotとか使ってれば良い感じの環境が整いそう。


VSCodeの人は自分で頑張ってください。


## プロジェクトの作成

まずHello worldするためにコンソールアプリケーション用のプロジェクトを作成する。

`dotnet new`という`Cargo init`みたいなコマンドがあるので、それを使ってプロジェクトを作成する。
ただし、デフォルトではC#のプロジェクトが作成されてしまうため、オプションで言語を指定する。
具体的には以下のようなコマンドを実行する。

`new`という名前がついているくせに**カレントディレクトリにファイルを展開する**ので、予めプロジェクト用のディレクトリを作って、その中で実行することをオススメする。うっかり実行してしまうとカレントにテンプレートファイルを撒き散らされて汚染されるので要注意。

`dotnet new console -lang "F#"`


実行が成功するとこんな感じのファイル達が生成される。

```
.
├── Program.fs
├── obj
│   ├── project.assets.json
│   ├── project.nuget.cache
│   ├── sample_project.fsproj.nuget.dgspec.json
│   ├── sample_project.fsproj.nuget.g.props
│   └── sample_project.fsproj.nuget.g.targets
└── sample_project.fsproj
```

この状態で`dotnet run`すると`Hello from F#`と表示される。
なんと一行もコードを書かずにHello worldしてしまった...最近の言語は需要を分かっていて良い。

## REPL

`dotnet fsi`コマンドを実行するとF#のインタプリタが起動する。
`printfn "Hello!";;`と打ってみると、こんな感じに表示されるはず。

```
> printfn "Hello!";;
Hello!
val it: unit = ()
```

型名も合わせて表示されたりと親切に作られているので、REPL回しながら小さいコード片をコピペしてプログラムを組んでいく、みたいな開発方法がやりやすい。

また、`.fsx`という拡張子はF#スクリプトとして扱われて、`dotnet fsi`で直接打ち込んだ扱いで実行される。
なのでビルドが走る`dotnet run`よりも実行されるまでが速い。

ただし、fsxは従来のF#と若干構文が違う。例えば、外部のパッケージを扱う際には`#r "nuget: ~`みたいな記述が必要になる。
事前にNugetの情報が与えられる`.fs`プログラムと違い、fsxがプロジェクトに依存しないため。
なので、外部パッケージに依存していても`.fsx`ならパッケージマネージャの操作が必要ない。いわば[Deno](https://deno.com/)的な使い方が可能になる。

例えば、`curl -s https://gist.githubusercontent.com/Comamoca/aa9a12a9bcb76365f01cd3094fd43cf2/raw/edda0b6ae816cd39f989c805a1a6aaf3794dbf52/precure.fsx | dotnet fsi --quiet`というコマンドを実行すると、カラフルな文字で**わんだふるぷりきゅあ!**と表示されるはず。

## Nugetパッケージをインストールする

F#は.NET上で実行されるため、他の.NET言語であるC#などと相互運用性がある。
つまり、C#で書かれたパッケージを普通に使うことができる。自分は始めてっきり特別な記法が必要なのだと思っていたのでこれには結構びっくりした。

それでは早速試してみる。まずNugetを検索できるサイトである。[nuget.org](https://www.nuget.org/)にアクセスする。

次に任意のパッケージを検索する。「TUI」とか漠然としたキーワードでも出てくるちゃ出てくる。

とは言いつつも、正直これで出てくるパッケージは動くかどうか信頼性がアレなので[awesome-fsharp](https://github.com/fsprojects/awesome-fsharp)から探した方がハズレがない。


次に、こんな画面になると思うので一番左側の`.NET CLI`というタブをクリックする。
すると画像みたいに`dotnet add package ~`と表示されるので、その右側にあるクリップボタンを押す。
これで`dotnet add package ~`の文言がクリップボードにコピーされた。

それをそのまま貼り付けて実行することでプロジェクトに該当のパッケージがインストールされる。

![](../../imgs/nuget_page.png)


カレントディレクトリにある`.fsproj`ファイルを開いて、

`<PackageReference Include="Spectre.Console.ImageSharp" Version="0.48.1-preview.0.28" />`

みたいな文言が新たに書き込まれていたらそのプロジェクトでパッケージを使う準備が整っている。
自分の環境ではインストール時に勝手に書き込まれているけども、
もし書き込まれていない場合はさっきのNugetsのページで`PackageReference`というタブを選択して`ItemGroup`タグの間に貼り付ける。これは新たに作っちゃっても大丈夫そう。

ちなみに、インストールしたパッケージは`dotnet list package`でも確認できる。ItemGroupまわりを書き換えたあとはこれで確認したほうが良さそう。

パッケージの削除は`dotnet remove パッケージ名`で行う。


## Paket

nugetの代わりにPaketというパッケージマネージャーを使うこともできる。
自分もこれを使っているけど、正直組み込みパッケージマネージャとそんなに変わらない。
ただ、依存管理を外部ツールに回せるのでそのあたりを弄りたいときに取り回しは良さそうではある。

まず始めにpaketをインストールする。

`dotnet tool install --global Paket`

次に初期化する。

`paket init`

次にインストール。例のNugetにPaketのタブがあるのでそこからクリックしてコピペして実行する。
こんな感じのコマンドになるはず。

`paket add Spectre.Console.ImageSharp --version 0.48.1-preview.0.28`

インストールが終わったら`paket show-installed-packages`コマンドでインストールされているパッケージを確認する。

パッケージの削除は`paket remove パッケージ名`で行う。


## 外部パッケージの読み込み方

ここからは実際に外部パッケージを読み込んで呼び出してみる。


他の言語の`import`に当たるものはF#では`open`キーワードになる。
> F#ではC#の関数などをシームレスに呼び出せる(わんだふる!)ので、結構いい感じにコードが書けるはず。
> ただ自分もそこまでC#との相互運用を試せてないので、これはまた後日別の記事でまとめていきたい。

参考までに、先ほど紹介したカラフルに**わんだふるぷりきゅあ!**と表示するプログラムの中身を貼ってみる。
これはf#スクリプトなので先頭に#rが付いている。普通のF#(.fs)ならこれは必要ない。

```fsharp
#r "nuget: Spectre.Console, 0.48.1-preview.0.28"
#r "nuget: FsSpectre, 0.4.6"
open Spectre.Console
open FsSpectre
let wa = "[#eb6ea6]わ[/]"
let nn = "[#c86fab]ん[/]"
let da = "[#5fbfb7]だ[/]"
let fu = "[#fdd000]ふ[/]"
let ru = "[#b1d155]る[/]"
let pu = "[#f5aa00]ぷ[/]"
let ri = "[#5fbfb7]り[/]"
let ki = "[#b1d155]き[/]"
let lyu = "[#b1d155]ゅ[/]"
let a = "[#eb6ea6]あ[/]"
let ex = "[#e39b78]![/]"
let ret = "\n"
AnsiConsole.Markup([wa; nn; da; fu; ru; pu; ri; ki; lyu; a; ex; ret] |> String.concat "")
```
95 changes: 53 additions & 42 deletions article/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,77 @@
## AIノート
- [AIノート](AIノート/README.md)

- [So Vits Svc&RVC](AIノート/So-vits-svc&RVC/README.md)

- [So Vits Svc](AIノート/So-vits-svc&RVC/So-vits-svc.md)
- [Stable Diffusion]()
- [AIノート](AIノート/Stable Diffusion/AIノート.md)
- [PaperSpaceでLoRAを使ったら学習を行う](AIノート/Stable Diffusion/PaperSpaceでLoRAを使ったら学習を行う.md)
- [もみじちゃんイラスト生成計画【Part1】](AIノート/Stable Diffusion/もみじちゃんイラスト生成計画【Part1】.md)
- [もみじちゃんイラスト生成計画【Part2】](AIノート/Stable Diffusion/もみじちゃんイラスト生成計画【Part2】.md)
- [プロンプトメモ](AIノート/Stable Diffusion/プロンプトメモ.md)

## Cotowali
- [Cotowali](Cotowali/Cotowali.md)

## Deno
- [Cotowali](Cotowali/Cotowali.md)
- [Deno](Deno/README.md)

- [Packages](Deno/Packages.md)
- [Deno Tui使い方メモ](Deno/deno_tui使い方メモ.md)

## Denoハンズオン

- [Denoの環境構築](Denoハンズオン/Denoの環境構築.md)
- [Denoハンズオン](Denoハンズオン/Denoハンズオン.md)
- [Denoハンズオン例題](Denoハンズオン/Denoハンズオン例題.md)
- [簡単TypeScript入門](Denoハンズオン/簡単TypeScript入門.md)

## Devcontainer
- [Devcontainer](Devcontainer/README.md)

- [コンテナの構築](Devcontainer/コンテナの構築.md)
- [Django](Django/README.md)

## Elixir
- [プロジェクトとApps](Django/プロジェクトとApps.md)
- [Elixir](Elixir/README.md)

- [Broadway](Elixir/Broadway.md)
- [ElixirのPlugでGleamを使う](Elixir/ElixirのPlugでGleamを使う.md)
- [Elixir始めたらとりあえず読んどけ](Elixir/Elixir始めたらとりあえず読んどけ.md)
- [GenStage](Elixir/GenStage.md)
- [Mix事始め](Elixir/Mix事始め.md)
- [Phoenix](Elixir/Phoenix.md)
- [Programs](Elixir/programs/README.md)

## Gleam
- [Lib]()
- [Test]()
- [Tips](Elixir/tips.md)
- [ビヘイビア](Elixir/ビヘイビア.md)
- [マクロ](Elixir/マクロ.md)

- [FSharp](FSharp/README.md)

- [Gleam](Gleam/README.md)

- [Actor](Gleam/Actor.md)
- [Gleam OTP](Gleam/Gleam OTP.md)
- [Gleam Pakeages](Gleam/Gleam Pakeages.md)
- [Process](Gleam/Process.md)
- [Supervisor](Gleam/Supervisor.md)
- [Task](Gleam/Task.md)
- [Tips](Gleam/Tips.md)
- [Wisp](Gleam/Wisp.md)
- [Elliメモ](Gleam/elliメモ.md)
- [Nakaiメモ](Gleam/nakaiメモ.md)
- [逆引きGleam](Gleam/逆引きGleam.md)
- [Godot](Godot/README.md)

## Godot

- [README](Godot/README.md)
- [ハウトゥーGodot征服](Godot/ハウトゥーGodot征服.md)


## Haxe
- [Haxe](Haxe/README.md)
- [Haxeのビルドまとめ](Haxe/Haxeのビルドまとめ.md)

## Nostr
- [Nostr](Nostr/README.md)
- [NIP-01](Nostr/NIP-01.md)

## HonKit
- [Haxeのビルドまとめ](Haxe/Haxeのビルドまとめ.md)
- [HonKit](HonKit/README.md)

## Lua
- [Lua](Lua/README.md)

- [Fennel](Lua/Fennel.md)
- [Teal](Lua/Teal.md)

## Misskeyアドカレ
Expand All @@ -77,64 +82,70 @@
- [ディレクトリ構成](Misskeyメモ/ディレクトリ構成.md)
- [認証](Misskeyメモ/認証.md)
- [起動](Misskeyメモ/起動.md)
- [Nostr](Nostr/README.md)

- [NIP 01](Nostr/NIP-01.md)
- [OCaml](OCaml/README.md)

- [OCamlでCLIツールを作りたい](OCaml/OCamlでCLIツールを作りたい.md)

## Obsidianハンズオン

- [Obsidianを使ってみよう](Obsidianハンズオン/Obsidianを使ってみよう.md)
- [Ruby](Ruby/README.md)

## Ocaml
- [RubyでNeovimプラグインを書く](Ruby/RubyでNeovimプラグインを書く.md)

- [README](OCaml/README.md)
- [OCamlでCLIツールを作りたい](OCaml/OCamlでCLIツールを作りたい.md)
## Rust

## Ruby
- [Ruby](Ruby/README.md)
- [RubyでNeovimプラグインを書く](Ruby/RubyでNeovimプラグインを書く.md)
- [Travis CIを使ってRustでバイナリ配布したい](Rust/Travis CIを使ってRustでバイナリ配布したい.md)

## Shell

- [Shrsを使ってみた](Shell/Shrsを使ってみた.md)

## Tips

- [KeybaseとGpg Preset Passphraseで良い感じにコミットを署名する](Tips/Keybaseとgpg-preset-passphraseで良い感じにコミットを署名する.md)
- [Ryeを使ったDjangoセットアップ](Tips/ryeを使ったDjangoセットアップ.md)
- [venvと使ったDjangoセットアップ](Tips/venvと使ったDjangoセットアップ.md)
- [Keybaseとgpg-preset-passphraseで良い感じにコミットを署名する](Tips/Keybaseとgpg-preset-passphraseで良い感じにコミットを署名する.md)

## Unity
- [Venvと使ったDjangoセットアップ](Tips/venvと使ったDjangoセットアップ.md)
- [Unity](Unity/README.md)

- [AnimeToolbox](Unity/AnimeToolbox.md)
- [MMDアニメーションメモ](Unity/MMDアニメーションメモ.md)
- [トゥーンレンダリング](Unity/トゥーンレンダリング.md)
- [VRChat](VRChat/README.md)

## Vim
- [LispでNeovimプラグインを書きたい](Vim/LispでNeovimプラグインを書きたい.md)
- [dpp.vimをLuaで設定する](Vim/dpp.vimをLuaで設定する.md)
- [init.lua大掃除](Vim/init.lua大掃除.md)
- [VimConf TinyのLTについて](Vim/VimConf TinyのLTについて.md)

## VRChat
- [OSC](VRChat/OSC.md)
- [Tolass Custom](VRChat/Tolass_custom.md)
- [VRCで外部通信](VRChat/VRCで外部通信.md)
- [Webカメラでフルトラッキング](VRChat/Webカメラでフルトラッキング.md)
- [World](VRChat/World.md)
- [アバターのQuest対応](VRChat/アバターのQuest対応.md)
- [スマホでQuest単騎腰トラ](VRChat/スマホでQuest単騎腰トラ.md)
- [ワールド自作](VRChat/ワールド自作.md)
- [衣装の着せ替え](VRChat/衣装の着せ替え.md)

## Vim

- [LispでNeovimプラグインを書きたい](Vim/LispでNeovimプラグインを書きたい.md)
- [VimConf TinyのLTについて](Vim/VimConf TinyのLTについて.md)
- [Dpp.VimをLuaで設定する](Vim/dpp.vimをLuaで設定する.md)
- [Init.Lua大掃除](Vim/init.lua大掃除.md)

## Zig

- [Zig](Zig/Zig.md)
- [Zigのstd.cryptoをNimで呼び出したかった](Zig/Zigのstd.cryptoをNimで呼び出したかった.md)
- [ZigのStd.CryptoをNimで呼び出したかった](Zig/Zigのstd.cryptoをNimで呼び出したかった.md)
- [例外処理](Zig/例外処理.md)

## Snippet
## Imgs

- [Snippet](snippet/README.md)

- [BERT Q&A](snippet/BERT Q&A.md)
- [GoでCLI兼ライブラリを作る](snippet/GoでCLI兼ライブラリを作る.md)
- [MiAuth](snippet/MiAuth.md)
- [Nim メタプロ](snippet/Nim メタプロ.md)
- [Spotify APIの認証方法](snippet/Spotify APIの認証方法.md)
- [エンカする際にやったほうがいいと思ったこと](snippet/エンカする際にやったほうがいいと思ったこと.md)
- [中国語メモ](snippet/中国語メモ.md)
- [言語モデルを自作する方法 By ChatGPT](snippet/言語モデルを自作する方法 by ChatGPT.md)
- [Spotify APIの認証方法](snippet/Spotify APIの認証方法.md)
Binary file added article/imgs/nuget_page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 731744a

Please sign in to comment.