F# Monkey

about

F#を気軽にテスト〜・それVimで

Summary

F#のコードをVimで手軽にテストしてみた

こんな感じ

必要なもの

  • Neovim
  • deoplete-fsharp

テストの仕方

  • Persimmonをゲッツ(Nuget, Paketおこのみで)
  • テストコードを書く
  • :Persimmonコマンドを実行

いいところ

気軽にテストできるところ(Persimmonコマンドを入力するだけ)

残念なところ

結果が出るまでに3秒ほどかかること

ちょっとした解説

Persimmonコマンドは以下のように動作します

同じフォルダに`Persimmon.Console.exe`があるか?
↓
同じフォルダに`tools`フォルダがあるか?(あればそのなかに`Persimmon.Console.exe`があるか?)
↓
同じフォルダに`Packages`フォルダがあるか?(あればそのなかに`Persimmon.Console.exe`があるか?)
↓
上記で見つからなければ`deoplete-fsharp`の`Persimmon.Console.exe`を使う






tutorial 01

Persimmon を使った簡単なテスト

paketコマンドはこちらを参照

// 実験フォルダをつくる
$ mkdir jikken

// 実験フォルダに移動
$ cd jikken

// paketを初期化
$ paket init

// ダウンロードするファイルをかく
$ vim paket.dependencies 

***********************
*
*   source https://www.nuget.org/api/v2
*   nuget Persimmon.Console -OutputDirectory tools -ExcludeVersion
*
***********************

// ダウンロード
$ paket install

// テストコードをかく
$ vim test.fsx

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon
open UseTestNameByReflection

let add   x y = x + y

let ``first test example`` = test {
    do! assertEquals 6 (add 1 5)
}

Persimmonコマンドを実行

: Persimmon

結果

.
============================== summary ===============================
run: 1, error: 0, violated: 0, skipped: 0, duration: 00:00:00.0934450


*** time : 3.035613 s ***


tutorial 02

tutorial 01 のつづき( jikken フォルダーにいるものとします)

依存のある`dll, exe`をサブフォルダにまとめる方法


dll, exeをまとめるlibフォルダをつくってPersimmonのサブフォルダにする

// libフォルダをつくる
$ mkdir lib

// コードをかく
$ vim ./lib/hello.fsx

code

namespace callmekohei

module Hello =

    let say (word:string) =
        word + " hello!"
// dllファイルを作成
$ fsharpc -a ./lib/hello.fsx

// libフォルダを Persimmon.Console.exe の下におく
$ mv  /lib packages/Persimmon.Console/tools/

ファイルの状況
jikken$ tree packages/
packages/
├── Paket
│   ├── Paket.nupkg
│   └── tools
│       └── paket.exe
└── Persimmon.Console
    ├── Persimmon.Console.2.0.1.nupkg
    ├── Persimmon.Console.nuspec
    ├── [Content_Types].xml
    ├── _rels
    ├── license.html
    ├── package
    │   └── services
    │       └── metadata
    │           └── core-properties
    │               └── coreProp.psmdcp
    └── tools
        ├── FSharp.Core.dll
        ├── Persimmon.Console.exe
        ├── Persimmon.Console.exe.config
        ├── Persimmon.Runner.dll
        ├── Persimmon.Runner.dll.config
        ├── Persimmon.dll
        ├── Persimmon.dll.config
        ├── System.ValueTuple.dll
        └── lib    <-------------------- sub foler!
            ├── hello.dll
            └── hello.fsx

10 directories, 17 files

設定ファイル(Persimmon.Console.exe.config)を書き直す

$ vim packages/Persimmon.Console/tools/Persimmon.Console.exe.config 

下記のようにかく(<probing privatePath="lib"/>を追加するだけ)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      
      <!-- Look for addins in the addins directory for now -->
      <probing privatePath="lib"/> 
      
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.4.1.0" newVersion="4.4.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

テストファイルを作成する

// テストファイル test2.fsx を作成する
$ vim test2.fsx

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon
open UseTestNameByReflection

#r "./packages/Persimmon.Console/tools/lib/hello.dll"
open callmekohei


let ``first test example`` = test {
    do! assertEquals "abc" ( Hello.say "hello" )
}

test実施(Persimmonコマンド実行)

: Persimmon

結果

x
begin Test2_deoplete-fsharp_temporary_file
Assertion Violated: first test example
1. Expect: "abc"
Actual: "hello hello!"
end Test2_deoplete-fsharp_temporary_file
============================== summary ===============================
run: 1, error: 0, violated: 1, skipped: 0, duration: 00:00:00.1194835


*** time : 2.941333 s ***

おまけ

超気軽なテスト

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon

let add   x y = x + y

assertEquals 1 ( add 1 1)
|> printfn "%A"

:QUICKRUNfsを実行

NotPassed (None,Violated "Expect: 1
Actual: 2")


*** time : 0.072349 s ***

これならはやい!

Remove all ads

dllファイルをサブフォルダーにおく

Summary

依存するdllファイルはexeファイルと同じフォルダに置くのが一般的

依存するdllをサブフォルダーに置く方法

方法

configファイルを作成する

ファイル構成

gimBeam.exeがメイン

highball$ tree
.
├── dll
│   ├── FSharp.Compiler.Service.dll
│   ├── FSharp.Core.dll
│   ├── Newtonsoft.Json.dll
│   ├── deopletefs.exe
│   └── log.txt
├── gimBeam.exe
├── gimBeam.exe.config
└── gimBeam.fsx

1 directory, 8 files

config ファイル

gimBeam.exe.configをつくって下記を入力

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

   <!-- Look for addins in the addins directory for now -->
      <probing privatePath="dll"/>

    </assemblyBinding>
  </runtime>
</configuration>

留意事項

依存するdllファイルは同じフォルダかサブフォルダしかおけない

privatePath は親フォルダを指定できない仕様
Remove all ads

F#をさっさと学ぶ〜( F#入門・学習)

Summary

F#を1年半お勉強して個人的に思ったことなど、など

1〜2週間ぐらいでさっさとF#を書きたい人向け

心構え

  • F#はそんなに難しくない

  • 難易度はPythonとかと同じでVBAよりも簡単

  • .netを活用することがキモになる

  • とかく日本語の情報がすくない(英語力がないと情報をとれない)

  • C#とか.netとかを当然知ってるでしょ?という前提で説明してくる人が多い(ビギナーにやさしくない)

  • 正直ビギナーには情報がなくて厳しいかも

レベル別学習方法

ビギナー

ビギナーのための本・チュートリアルはないような気がする・・・

初級

fsharpintro.net

中級

実践 F# 関数型プログラミング入門

実践 F# 関数型プログラミング入門

プログラミングF#

プログラミングF#

上級(英語を読める力が必要)

www.gitbook.com

F# Programming - Wikibooks, open books for an open world

リファレンス(ど忘れした時とかに便利)

github.com

今後に期待(今は作成中っぽい・・・)

docs.microsoft.com

お勉強中にわからなかったら

  • まず本とかネットとかで情報をさがす

  • チャット(gitter)で聞いてみる(Githubのアカウントが必要)

  • チャット(slack)で聞いてみる(登録が必要)

  • 質問サイト(stackoverflow)で聞いてみる(登録が必要)

  • Twitterで聞いてみる(#fsharpとつけるといいかも?)

Remove all ads

なんとなく FizzBuzz かいてみた

なんかハイボール片手にツイッターをぼけ〜っとみてたら

FizzBuzzしたくなったのでかいてみた!

こんな感じ

コード

fizzbuzz.fsx

#load "./interaction.fsx"
open callmekohei.Interaction

let (|Div|_|) by n = if n % by = 0 then Some Div else None

let fizzbuzz = function
    | Div 15 -> "FizzBuzz"
    | Div  5 -> "Buzz"
    | Div  3 -> "Fizz"
    | n      -> string n

let rec main s =
    match s with
    | "init" -> stdout.WriteLine("--- start ---")
                main ( stdin.ReadLine() )
    | "quit" -> printer.Quit()
    | _ when fst (System.Int32.TryParse(s)) = false -> 
        stdout.WriteLine("数字を入力してください!")
        main ( stdin.ReadLine() )
    | _      -> printer.WriteLine(fizzbuzz(int s))
                main ( stdin.ReadLine() )

main "init"

interaction.fsx

namespace callmekohei
module Interaction =

    type PrinterAgent() =
        let inbox = MailboxProcessor.Start( fun inbox ->
            let rec loop () = async {
                let! ( msg : Choice< string , AsyncReplyChannel<unit> > ) = inbox.Receive()
                match msg with
                | Choice1Of2 (s:string) ->
                    stdout.WriteLine(s)
                    return! loop ()
                | Choice2Of2 (ch : AsyncReplyChannel<unit>) -> ch.Reply ()
            }
            loop ()
        )

        member x.WriteLine(s) = inbox.Post ( Choice1Of2 s )
        member x.Quit()       = inbox.PostAndReply(fun ch -> Choice2Of2 ch)

    let printer = PrinterAgent()

みどころ〜

アクティブパターンなところ

数字かどうか判定〜

mailboxporcessorをつかってるところ〜(マルチスレッドでも安全!)
Remove all ads

F#で簡単プロセス間通信

Summary

親子プロセスでの通信

こんな感じ

$ mono abc.exe 
HELLO from child process
hello --- from child process --- 
apple
apple --- from child process --- 
banana
banana --- from child process --- 
cherry
cherry --- from child process --- 
quit

$ 

子プロセス

文字を入力するとabc --- from child process ---と返す

let rec main s =
    match s with
    | "quit" -> ()
    | "init" -> stdout.WriteLine("HELLO from child process")
                main ( stdin.ReadLine() )
    | _      -> stdout.WriteLine( s + " --- from child process --- " )
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "init"
    0

親プロセス

親プロセスで文字を入力

→ 子プロセスに文字を送る

→ 子プロセスの標準出力が出力されたら取得する(イベントで見張ってる)

open System.Diagnostics

type Interaction (fp:string, args:string, wd:string) =
    
    // 子プロセスの起動パラメータを作成する
    let procStartInfo =
        ProcessStartInfo(
            FileName               = fp   ,
            Arguments              = args ,
            WorkingDirectory       = wd   ,
            RedirectStandardInput  = true , // 子プロセスの標準入力をリダイレクトする
            RedirectStandardOutput = true , // 子プロセスの標準出力をリダイレクトする
            RedirectStandardError  = true , // 子プロセスの標準エラーをリダイレクトする
            UseShellExecute        = false  // シェルを使用せず子プロセスを起動する(リダイレクトするために必要)
    )
    
    // 子プロセスをインスタンス化
    let ps = new Process(StartInfo = procStartInfo)

    // Set our event handler to asynchronously read the ps output.
    // リダイレクトした標準出力の内容を受信するイベントハンドラを設定する
    do ps.OutputDataReceived
       |> Event.add ( fun (args :DataReceivedEventArgs) ->
           stdout.WriteLine(args.Data) |> ignore )
    
    // 子プロセスを起動する
    do ps.Start() |> ignore
    // 子プロセスがアイドル状態になるまで無期限に待機
    do ps.WaitForInputIdle() |>ignore
    // Start the asynchronous read of the ps output stream.
    // 標準出力の非同期読み込みを開始する
    do ps.BeginOutputReadLine()

    // リダイレクトした子プロセスの標準入力にテキストを書き込む
    member this.Send(message:string) = ps.StandardInput.WriteLine(message)
    
    // 子プロセスを終了する
    member this.Quit() = ps.Kill()



let mono    = "/usr/local/Cellar/mono/4.8.1.0/bin/mono"
let args    = "/Users/kohei/Documents/childProcess.exe"
let workdir = "/Users/kohei/Documents/"
let replyer = Interaction(mono,args,workdir)

let rec main s =
    match s with
    | "quit" -> replyer.Quit()
    | _      -> replyer.Send(s)
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "hello"
    0
Remove all ads

TravisからGithubにpushしてみた〜

f:id:callmekohei00:20170709142719p:plain

Summary

TravisからGithubpushしてみた

かなりハマったのでメモメモ。

はまり

下記が表示されて処理が前に進まない・・・

$ git clone git@github.com:callmekohei/deoplete-fsharp-bin.git
Cloning into 'deoplete-fsharp-bin'...
Enter passphrase for key '/home/travis/.ssh/id_rsa': 

原因

(その1)

passphraseを設定した

$ ssh-keygen -f deploy_key

keyを作る際にりーたん・りたーんするところを何かしらキーを押したっぽい?

(その2)

sshの設定?

一応下記のようにして ~/.ssh/configappendした

Host github.com
    User git
    StrictHostKeyChecking no
    IdentityFile ~/.ssh/id_rsa
    IdentitiesOnly yes
    ForwardAgent yes

(その3)

gitリポジトリを作り直すとだめになる?

多分最初のpushはだめかも。。。

対処

結局、再度キーペア作り直すと

ちゃんとうごきました

手順

gist.github.com

参考

www.tam-tam.co.jp

Remove all ads

easy debug with deoplete source

Summary

easy debug with deoplete source

Method

(step 1) use debug function

from .base import Base
from deoplete.util import debug # <--- point!!!

class Source(Base):
    def __init__(self, vim):
        super().__init__(vim)
        self.name = 'callmekohei'
        self.mark = '[callmekohei]'
        self.filetypes = ['text']

    def gather_candidates(self, context):
        debug(self.vim,"callmekohei") # <--- point!!!
        return ["apple","banana","cherry"]


(step 2)

: set cmdhight=3
Remove all ads

FParsecのメモ

たんなる雑記メモですっ

#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsecCS.dll"
#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsec.dll"
open FParsec

"hello world" |> run (many letter) |> printfn "%A"
/// Success: ['h'; 'e'; 'l'; 'l'; 'o']

"hello world" |> run (manyChars letter) |> printfn "%A"
/// Success: "hello"

"hello world" |> run ( sepBy (manyChars letter) (pchar ' ')) |> printfn "%A"
/// Success: ["hello"; "world"]

"hello, world"
|> run (sepBy ( manyChars letter ) ( pstring "," .>> spaces ))
|> fun x -> match x with Success (lst,_,_) -> lst | _ -> []
|> printfn "%A"
/// ["hello"; "world"]

"hello00 world99"
|> run (sepBy (manyChars (letter <|> digit)) (pchar ' ')) |> printfn "%A"
/// Success: ["hello00"; "world99"]

"hello00 world99"
|> run (sepBy ( (manyChars letter) .>> (manyChars digit) ) (pchar ' ')) |> printfn "%A"
/// Success: ["hello"; "world"]
Remove all ads

FParsecをさわってみた!

Summary

文字をパースするFParsecというライブラリを触ってみました

こんなかんじ

#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsecCS.dll"
#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsec.dll"
open FParsec

let test p str =
    match run p str with
    | Success(result, _, _)   -> printfn "Success: %A" result
    | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg

test pfloat "1.25" /// Success: 1.25

ポイント

dllに優先順位(依存関係)があるので上記のようにFParseCS.dllを上に書いてからFParse.dllをかく

参考

Tutorial

還暦プログラマの挑戦(Haskell に挑む→F#による言語造り)

komorebikoboshi.hatenablog.com

hafuu.hatenablog.com

Remove all ads

F#のMailboxProcessorのメモ

シンプルなエージェント

/// エージェントを作成する( Queueに入れるタイプを指定する、async式を返す式を指定する)
let simpleAgent = new MailboxProcessor<string>(fun _ -> async { () })

/// Queueに文字を入れる
simpleAgent.Post("hello")

/// Queueに入ってる文字列の数を調べる
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 1

simpleAgent.Post("world")
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 2

/// Queueに入ってる文字列をすべて調べる
simpleAgent.TryScan( fun x ->
    stdout.WriteLine(x)
    if x = null then Some(async{()}) else None
,timeout = 1) |> Async.RunSynchronously |> ignore
// hello
// world

/// Queueからエージェント側に文字列を取得する
simpleAgent.Receive() |> Async.RunSynchronously |> stdout.WriteLine // hello

/// Queueに入ってる文字列の数を調べる
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 1

simpleAgent.Receive() |> Async.RunSynchronously |> stdout.WriteLine // world
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 0

エージェントから値を取得する

let replyAgent = MailboxProcessor.Start( fun inbox ->
    async {
        let! (ch:AsyncReplyChannel<_>) = inbox.Receive()
        ch.Reply "hello"
    }
)
replyAgent.PostAndReply id |> stdout.WriteLine
/// hello

FizzBuzzしてみた

let (|Div|_|) by n = if n % by = 0 then Some Div else None

let fizzbuzz = function
    | Div 15 -> "FizzBuzz"
    | Div  5 -> "Buzz"
    | Div  3 -> "Fizz"
    | n      -> string n

type Command = Add of int | Fetch of AsyncReplyChannel<string list>

let fizzbuzzAgent = MailboxProcessor.Start( fun inbox ->
    
    let rec loop lst = async{
        let! msg = inbox.Receive()
        match msg with
        | Add value ->
            return! loop ( fizzbuzz value :: lst )
        | Fetch ch ->
            ch.Reply(lst)
            return! loop lst
    }
    loop []
)

[1..100] |> List.iter( fun n -> fizzbuzzAgent.Post(Add n) )

fizzbuzzAgent.PostAndReply(Fetch)
|> List.rev
|> List.iter stdout.WriteLine

結果

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
以下略

ちょっとした電卓

type Command = AllClear | Add of int | Enter of AsyncReplyChannel<int * Command list>
    
let CalcAgent = MailboxProcessor.Start( fun inbox -> 

    let rec loop n lst = async {
        match inbox.Receive() |> Async.RunSynchronously with
        | AllClear   -> return! loop 0 []
        | Enter repl -> repl.Reply( n , lst |> List.rev ) ; return! loop n lst
        | Add value  -> return! loop (value + n) ( Add value   :: lst )
    }
    loop 0 []
)

CalcAgent.Post(Add 8)
CalcAgent.Post(Add 5)
CalcAgent.Post(Add -3)
CalcAgent.PostAndReply(Enter) |> printfn "%A"
/// (10, [Add 8; Add 5; Add -3])

CalcAgent.Post(AllClear)

CalcAgent.Post(Add 1)
CalcAgent.Post(Add 5)
CalcAgent.Post(Add -2)
CalcAgent.PostAndReply(Enter) |> printfn "%A"
/// (4, [Add 1; Add 5; Add -2])
Remove all ads

F#でprintデバッグしてみる〜

sample code

コードはこんな感じで

open System.Diagnostics

/// Debugモードのときだけコンパイルする
#if DEBUG
/// リスナーをインスタンス化する
let listener  = new DefaultTraceListener()
/// logファイルを指定する
let parentDic = System.Reflection.Assembly.GetEntryAssembly().Location |> fun x -> string ( System.IO.Directory.GetParent(x) )
listener.LogFileName <- System.IO.Path.Combine( parentDic, "log.txt" )
/// リスナーに追加する
Debug.Listeners.Add(listener)
#endif

let rec main s (acc:int)=
    match s with
    | "quit" -> () /// quitという文字列で終了する
    | _      -> 
                /// stdoutから出力する
                stdout.WriteLine(s)
                /// log.txtに出力する
                Debug.WriteLine(acc)
                main (stdin.ReadLine()) (acc + 1)

[<EntryPointAttribute>]
let entry arg =
    main arg.[0] 0
    0

デバッグのしかた

まずdebugモードでコンパイル

$ fsharpc -d:DEBUG abc.fsx

で、ログファイルをリッスン

Fを押してForward foreverとする

$ less log.txt

実行してみる

$ mono abc.exe callmekohei
/// 標準出力へ
callmekohei
/// log.txtへ
0
Remove all ads

Neovimでお手軽にF#書けるようにしてみた〜

f:id:callmekohei00:20170608202917p:plain



いままでプログラムを実行するのにbash script別途必要でしたが不要になりました!

下記のコマンドですぐにF#Hello, World!できますっ!

# deinを使ってのインストール例

call dein#add('Shougo/deoplete.nvim')
call dein#add('callmekohei/deoplete-fsharp')

よかったらぜひ〜

ソースはこち

github.com

課題

オートコンプリートでhttpをつかってるのですがこれを普通のアプリに変えたい〜(stdin/stdouを使いたい)

オートコンプリートのOne word hintsを改善したい〜

Remove all ads

Neovim + Python-client で Quickrun もどきをつくってみた!

こんな感じ

Motivation

deoplete-fsharpquickrunしようとすると

thinca/vim-quickrunだとbash scriptが必要になるので

それがめんどくさかったのです、です

感想

neovim + python-client だと、むずかしいvim scriptを書かなくて済むのでたすかる〜

暗黒さん@ShougoMatsuさんのdeopleteのコードをがむしゃらに読んで参考にしました〜

thinca/vim-quickrunneovim(async)に対応しないかな〜 (thincaさん!お願いします!)

課題

ファイルタイプがfsxの時だけ:QuickRunfsがでるようにしたい

実行結果を一時バッファに出してるのですが、その時の画面のちらつき?をなくしたい

ファイルはこち

github.com

fsi(FSharp Interacrive) はこち

こんかいはfsiweb serverに載せずにコンソールアプリにしてみました!

github.com

追記

2017/06/07 21:00

てらむさん@termoshttからファイルタイプがfsxの時にだけ

コマンドが出るようにする方法を教えていただきました!

ありがとうございます!!!!

こんな感じにします!

import neovim

@neovim.plugin
class quickrunfsHeader(object):

    def __init__(self, vim):
        self._vim = vim

    @ neovim.function('PyQuickRunFs', sync=True)
    def fsiShow(self,arg):
        # something...

    @ neovim.autocmd("BufEnter", "*.fsx")
    def reg_quickrun_fs(self):
        self._vim.command("command -buffer QuickRunfs :call PyQuickRunFs()")
Remove all ads

こんにちは世界でF#入門〜

さくっと浅くF#をお勉強してみる〜

こんにちはせかい

"hello world" |> stdout.WriteLine

ラベルをつけてみる

let hello = "hello"
let world = "world"

hello + " " + world |> stdout.WriteLine

大文字にしてみる

hello + " " + world |> fun s -> s.ToUpper() |> stdout.WriteLine

3回こんにちはせかいと言ってみる

/// (ループしてみる)
for i in [1..3] do
    stdout.WriteLine "hello world"


/// (イテレートしてみる)
[1..3]
|> List.iter ( fun _ -> stdout.WriteLine "hello world" )


/// こんにちは世界のシーケンスを先に作ってイテレート
Seq.init 3 ( fun _ -> "hello world" )
|> Seq.iter stdout.WriteLine


/// 文字列を作ってそれを印字
"hello world"
|> fun s -> String.replicate 3 ( s + "\n" )
|> stdout.WriteLine

asyncでやってみる

[ async{return "hello"}; async{return "world"} ]
|> Async.Parallel
|> Async.RunSynchronously
|> Array.iter stdout.WriteLine

RX with eventでやってみる

let e = Event<_>()

e.Publish
|> Observable.add( fun (e:string) -> stdout.WriteLine(e) )

e.Trigger("hello world")




ふむふむ

F#マスターした!www

Remove all ads

Vimの操作を効率的に学ぶための6つのエクササイズ〜

ぜんぜん足りないとはおもいますけど

vimの操作の勘所をエクササイズ形式で

まとめてみました〜 (^_^)/

01

extragrouptexts

↓

extraGroupTexts

hints

f find

~ large letter / small letter

02

abc

↓

bbc

↓

BBC

hints

r replace

viw select word

~ large letter / small letter

03

{apple}"banana"<cherry>{APPLE}"BANANA"<CHERRY>

hints

vi{ select inside {}

~ large letter / small letter

04

.btn-large {
    padding     : 12px 19px ;
    font-size   : 16px      ;
    line-height : normal    ;
    font-weight : bold      ;
}.btn-large {
    font-size   : 16px      ;
    font-weight : bold      ;
    line-height : normal    ;
    padding     : 12px 19px ;
}

hints

vi{ select inside {}

:'<,'>sort sort

05

let abc = {


}let abc = {
    
    }

hints

v(line number)G $ select

shift > indent

06

let Say ( sq:seq<string> ) : unit =
   sq |> Seq.iter stdout.WriteLine

let threeTimes word =
   Seq.init 3 ( fun _ -> word )

threeTimes "hello" |> Say

↓

let threeTimes word =
   Seq.init 3 ( fun _ -> word )

let Say ( sq:seq<string> ) : unit =
   sq |> Seq.iter stdout.WriteLine

threeTimes "hello" |> Say

hints

vjj select

:'<,'>m 6 move


練習用テキスト

( ex1 )
extragrouptexts


( ex2 )
abc


( ex3 )
{apple}"banana"<cherry>


( ex4 )

.btn-large {
    font-size   : 16px      ;
    font-weight : bold      ;
    line-height : normal    ;
    padding     : 12px 19px ;
}


( ex5 )

let abc = {


}

( ex6 )

let Say ( sq:seq<string> ) : unit =
   sq |> Seq.iter stdout.WriteLine

let threeTimes word =
   Seq.init 3 ( fun _ -> word )

threeTimes "hello" |> Say
Remove all ads