LangExtの紹介 - シーケンスの生成

[前回はシーケンスの概要を紹介](http://qiita.com/items/5d1f51ce45356a12ac74)しました。

今回は、シーケンスの生成について紹介します。

using
-----
例に出すLangExtを使ったコードは、System名前空間とLangExt名前空間がusingされているものとします。

シーケンスの生成方法
--------------------
シーケンスを生成する方法はいくつかあります。

* Enumerable.ToSeq
* Seq.Empty / Seq.Singleton
* Seq.Create / Create.Seq
* Seq.Init / Seq.InitInfinite
* Seq.Repeat / Seq.RepeatInfinite
* Seq.Unfold

他にもありますが、代表的には上に挙げた方法で生成することになります。
今回は、`Seq.Unfold`以外を紹介します。
`Seq.Unfold`は、Optionの紹介が終わってからか、`Seq.Fold`を説明するときに紹介します。

### Enumerable.ToSeq - IEnumerable[T]を変換
`Enumerable.ToSeq`メソッドは、`IEnumerable[T]`を`ISeq[T]`に変換するメソッドです。
`IEnumerable[T]`に対する拡張メソッドとして定義されているため、

```csharp
var seq = new[] { 1, 2, 3 }.ToSeq();
```

のように呼び出せます。
他のライブラリ(標準ライブラリ含む)からLangExtを採用したAPI側へデータを渡したいときに使います。

### Seq.Empty / Seq.Singleton - 0 / 1要素のシーケンスを生成
`Seq.Empty`はいいでしょう。`System.Linq.Enumerable.Empty`に相当します。
`Seq.Singleton`は、指定した要素を1つ含むシーケンスを生成します。
標準クエリ演算子では、

```csharp
// using System.Linq;されているとする
var empty1 = Enumerable.Repeat(x, 1);
// もしくは、
var empty2 = new[] { x };
```

のように記述します。
前者はすぐに頭に入ってきませんし、少し長いです(補完を活用しても、「Enume<Ctrl+Space>.Rep」)。
後者は短いですが、記号が打ちにくい並びで並んでいるためか何なのか、一発でちゃんと打てません(個人的な問題でごめんなさい)。

これに対して、LangExtでは

```csharp
var empty = Seq.Singleton(x);
```

と、それなりに書きやすく(Seq.Siまでで補完が効く)、`Repeat(x, 1)`よりもより意図を素直に表せます。

また、「Tを受け取ってISeq[T]を返す関数」を受け取る高階関数があった際に、そのTの値一つのみを含むシーケンスでいい場合は以下のように書けます。

```csharp
// void Something(Func<int, ISeq<int>> f); という関数があったとして
Something(Seq.Singleton);

// Repeatの場合
Something(x => Seq.Repeat(x, 1));

// 配列リテラルの場合(fがISeq<int>ではなく、IEnumerable<int>を返す関数だった場合
Something(x => new[] { x });
```

`Seq.Singleton`以外は、ラムダ式が必要になってしまいます。

ちなみに、Singletonという名前はF#由来です(参考: [Seq.singleton](http://msdn.microsoft.com/ja-jp/library/vstudio/ee353705.aspx))。

### Seq.Create / Create.Seq
LangExtでは、「モジュール名.Create」を提供している場合に、「Create.型名」という関数を提供しています。
モジュール名のルールはありますが、いちいち覚えるのは面倒です。
そこで、(LangExt内で)統一的に使える「Create」モジュールを提供しています。

Seq.Create / Create.Seqは可変長引数を取る関数として定義されており、渡した要素を含むシーケンスを生成します。

```csharp
var seq = Create.Seq(10, 20, 30);
```

配列を受け取ってシーケンスを返す関数を受け取る関数があった場合に、何もせずにシーケンスに変換したい場合は以下のように書けます。

```csharp
// void Something(Func<int[], ISeq<int>> f); という関数があったとして
Something(Create.Seq);
```

### Seq.Init / Seq.InitInfinite
`Seq.Init`は、要素数と関数を指定してシーケンスを生成し、`Seq.InitInfinite`は関数のみを指定してシーケンスを生成する関数です。
Infiniteという語に反して、`int.MaxValue`個の要素までしか正常に扱えないことに注意してください。

この2つの関数は、非常に便利ですが、標準クエリ演算子に対応するものはありません。
例えば「2の倍数の数列の先頭10要素がほしい」と思った場合、標準クエリ演算子では以下のように書くでしょう。

```csharp
// System.Linq名前空間がusingされているとする
var res = Enumerable.Range(0, int.MaxValue).Where(i => i % 2 == 0).Take(10);
```

LangExtでは、`Seq.Init`を使って、以下のように記述できます。

```csharp
var res = Seq.Init(10, i => i % 2 == 0); // iには先頭から何番目の要素かが渡されてくる
```

LangExtを採用しないとしても、この関数は自分の道具箱に入れておくべきでしょう。

ちなみに、この2つの関数はF#由来です(参考: [Seq.init](http://msdn.microsoft.com/ja-jp/library/ee370244.aspx) / [Seq.initInfinite](http://msdn.microsoft.com/ja-jp/library/ee370429.aspx))。

Seq.Repeat / Seq.RepeatInfinite
-------------------------------
`Seq.Repeat`は、要素数と要素を指定してシーケンスを生成し、`Seq.RepeatInfinite`は要素のみを指定してシーケンスを生成する関数です。
Infiniteという語に反して、`int.MaxValue`個の要素までしか正常に扱えないことに注意してください。

`Seq.Repeat`は`System.Linq.Enumerable.Repeat`に相当します。

`Seq.RepeatInfinite`は、要素数を指定しないバージョンなので説明はいいでしょう。
この関数がない場合、

```csharp
// System.Linq名前空間がusingされているとする
var seq = Enumerable.Range(0, int.MaxValue).Select(_ => x);
```

のように書く必要があります。

標準クエリ演算子に存在して、LangExtに存在しない生成関数
-------------------------------------------------------
### DefaultIfEmpty
`DefaultIfEmpty`は簡単に`null`を持ち込むので、そのまま提供するつもりはありませんでした。
かと言っていい案があるわけではなかったので、2.0では実装しませんでした。

LangExt2.0リリース直前に`Unsafe`名前空間を導入したときに、その中に含めようかとも思ったのですが、
あくまでもこの名前空間は「例外を投げうる」という関数の置き場所に限定したかったのです。

今のところ、`Null`名前空間を導入し、そちらに入れることも考えていますが、まだ決定ではありません(その場合、構造体に対しては`T?`を返すようにして、NullIfEmptyとでも名前を変えましょうか)。

### Range
`Range`は、第二引数が要素数なのかシーケンスの長さなのかがわかりにくいため、提供しません。
その代りに、Range型を導入予定です。

```csharp
// Range型による実現
public struct Range
{
    ...
    public ISeq<int> ToSeq() { ... }
}
```

`Range`を提供し、第二引数は幽霊型にする、という案もたった今思いついたので、もしかするとそうなるかもしれません。

```csharp
// 幽霊型による実現
public interface IUnit {}
public struct IntWithUnit<TUnit> where TUnit : IUnit { ... }

public struct Length : IUnit { ... }
public struct Position : IUnit { ... }

public static class LengthModule
{
    public static IntWithUnit<Length> Len(this int length) { ... }
}
public static class PositionModule
{
    public static IntWithUnit<Position> Pos(this int position) { ... }
}

public static class Seq
{
    public static ISeq<int> Range(int start, IntWithUnit<Length> len) { ... }
    public static ISeq<int> Range(int start, IntWithUnit<Position> end) { ... }
}

var seq = Seq.Range(0, 10.Len());
```

どちらも用意する、というのもアリなのでしょうか。おとーふさんとも相談ですね。

次回
----
次回は、[長さ取得系のメソッド](http://qiita.com/items/aba144e26d07b23e8ef8)についてです。