想在工作用得上的 side-project 裡試試 Frege 。初衷是：如果大家都在 production 用 FP language ，我也必須這樣。不然經驗永遠不夠，只能把 FP 當玩具。

[Frege: Hello Java - mmhelloworld][Frege-Hello-Java] 介紹了如何用 Frege 跟 Java 溝通，可以看到不純的 class 要放在長長的 `ST s (Mutable s (ClassName a))` 中，可以簡寫成 `STMutable s (ClassName a)` 。

`ST s a` 的說明可以在 [PreludeBase.fr][PreludeBase.fr] 中找到：

> @(ST s a)@ is an abstract data type and is
> a computation that encapsulates side effects in state thread @s@
> and returns a value of type @a@.

配上 [talios/frege-testing][frege-testing] ，只靠 `mvn compile exec:exec` 就把程式跑起來！

Frege 社群有個工具， [Frege/frege-native-gen][frege-native-gen] ，能幫忙自動產生和 Java classes 溝通的程式碼，但我打算先自己寫幾次，了解 `ST s a` 到底是什麼、用起來是什麼感覺後，再學工具。

[Frege-Hello-Java]: http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/
[PreludeBase.fr]: https://github.com/Frege/frege/blob/master/frege/prelude/PreludeBase.fr
[frege-testing]: https://github.com/talios/frege-testing
[frege-native-gen]: https://github.com/Frege/frege-native-gen

## 接接看 Apache.POI

來看看要怎麼包 `HSSFWorkbook` 這種實用的 lib 。

首先我們需要把 Java constructor 包起來：

```Frege
data HSSFWorkbook = native org.apache.poi.hssf.usermodel.HSSFWorkbook where
  native new :: () -> ST s (Mutable s HSSFWorkbook)
```

其中 `ST s (Mutable s HSSFWorkbook)` 可以[簡寫][STMutable]為 `STMutable s HSSFWorkbook` ，兩個 `s` 的 type 相同：

```Frege
data HSSFWorkbook = native org.apache.poi.hssf.usermodel.HSSFWorkbook where
  native new :: () -> STMutable s HSSFWorkbook
```

接著處理 `HSSFWorkbook::write` ：

```Frege
data HSSFWorkbook = native org.apache.poi.hssf.usermodel.HSSFWorkbook where
  native new :: () -> STMutable s HSSFWorkbook
  native write :: MutableIO HSSFWorkbook -> OutputStream -> IO ()
    throws IOException
```

`MutableIO` 是 `Mutable RealWorld` 的[別名][MutableIO]， `IO` 是 `ST RealWorld` 的[別名][IO]。還有個現在沒出現的 `IOMutable` 是 `IO MutableIO` 的[別名][IOMutable]。

[STMutable]: https://github.com/Frege/frege/blob/master/frege/prelude/PreludeIO.fr#L318
[MutableIO]: https://github.com/Frege/frege/blob/master/frege/prelude/PreludeIO.fr#L297
[IO]: https://github.com/Frege/frege/blob/master/frege/prelude/PreludeBase.fr#L2014
[IOMutable]: https://github.com/Frege/frege/blob/master/frege/prelude/PreludeIO.fr#L314

---

接著還需要產生 `HSSFSheet` ，在 `HSSFWorkbook` 中加上 `createSheet` function ：

```Frege
data HSSFWorkbook = native org.apache.poi.hssf.usermodel.HSSFWorkbook where
  native new :: () -> STMutable s HSSFWorkbook
  native createSheet :: Mutable s HSSFWorkbook -> String -> STMutable s HSSFSheet
  native write :: MutableIO HSSFWorkbook -> OutputStream -> IO ()
    throws IOException
```

補上其他 type ：

```Frege
data HSSFSheet = native org.apache.poi.hssf.usermodel.HSSFSheet where
  native createRow :: Mutable s HSSFSheet -> Int -> STMutable s Row
  
data Cell = native org.apache.poi.ss.usermodel.Cell where
  native setCellValue :: Mutable s Cell -> String -> ST s ()

data Row = native org.apache.poi.ss.usermodel.Row where
  native createCell :: Mutable s Row -> Int -> STMutable s Cell
```

處理一下例外：

```Frege
pure native showThrowable toString :: Throwable -> String
```

---

整個寫起來像這樣：

```Frege
module frege.Main where

data HSSFSheet = native org.apache.poi.hssf.usermodel.HSSFSheet where
  native createRow :: Mutable s HSSFSheet -> Int -> STMutable s Row

data HSSFWorkbook = native org.apache.poi.hssf.usermodel.HSSFWorkbook where
  native new :: () -> STMutable s HSSFWorkbook
  native createSheet :: Mutable s HSSFWorkbook -> String -> STMutable s HSSFSheet
  native write :: MutableIO HSSFWorkbook -> OutputStream -> IO ()
    throws IOException

data Cell = native org.apache.poi.ss.usermodel.Cell where
  native setCellValue :: Mutable s Cell -> String -> ST s ()

data Row = native org.apache.poi.ss.usermodel.Row where
  native createCell :: Mutable s Row -> Int -> STMutable s Cell

pure native showThrowable toString :: Throwable -> String

main _ = do
  let filename = "out.xls"
  workbook <- HSSFWorkbook.new ()
  sheet <- HSSFWorkbook.createSheet workbook filename
  row <- HSSFSheet.createRow sheet 0
  cell <- Row.createCell row 0
  Cell.setCellValue cell "hello, world"
  file <- File.new filename
  out <- FileOutputStream.new file
  try (\book -> HSSFWorkbook.write book out) workbook
    `catch` (\(exception :: IOException) -> println $ showThrowable exception)

```

再來要挑戰 [Vert.x][vertx.io] ！

[vertx.io]: http://vertx.io/
