2011-12-26 4 views
5

有限状態機械を書くときに、ハスケルの "無限型"に遭遇しました。私は次のように非常に直感的だと思った:ハスケルの無限型と私のFSM関数

fsm []  _  acc = Right acc 
fsm (x:xs) state acc = 
    case state acc x of 
     Left err  -> Left err 
     Right (s, a) -> fsm xs s a 

私は状態関数現在の状態(アキュムレータ)と新しいイベントを与え、状態関数は、新しいアキュムレータと一緒に次の状態関数を生成します。私はもうイベントがなくなるまで再発する。

コンパイラは私に語った:

Occurs check: cannot construct the infinite type: 
    t1 = b0 -> t0 -> Either a0 (t1, b0) 
In the second argument of `fsm', namely `s' 

stateは今無限タイプですので。どのように私はそれを動作させるためにこれを並べ替えるには?

答えて

8

このような無限のタイプはタイプシステムで大混乱です。彼らはそれを危険にするものではありませんが、あなたが本当に欲しくないタイプのプログラムを多量に発生させ、エラーを隠してしまい、タイプ推論をより困難にすると信じています。

ありがたいことに、解決策は簡単です:newtypeラッパーを作成するだけです。 datanewtype宣言はもちろん再帰的にすることができます(そうでなければ、リストも定義できませんでした)。それは単なる平らで、包まれていないタイプではありません。

newtype FSMState err acc ev = 
    FSMState { stepFSM :: acc -> ev -> Either err (FSMState err acc ev, acc) } 

fsm :: [ev] -> FSMState err acc ev -> acc -> Either err acc 
fsm []  _  acc = Right acc 
fsm (x:xs) state acc = 
    case stepFSM state acc x of 
     Left err  -> Left err 
     Right (s, a) -> fsm xs s a 
+0

ありがとうございます。私にとって、これは無限の型に名前を付けることですが、型自体はまだ自己参照しています。コンパイラ自体も同じように無限型に名前を付けました。私は、コンパイラが名前を付けることでこれを自動化できると思っていただろう。私は間違っていますか? – Ana

+5

@Ana:Haskellはあなたのプログラムが* choice *によって無効であると判断し、必要ではないと考えているのは事実ですが、それは非常に良い理由です。現在、私はリンクがありませんが、チェックする型システムに依存する*多くの一般的なエラー - 引数の欠落や関数名の2回の書き方など - 無制限に許可すると、型付きの(壊れた)プログラムになりますタイプ。 – ehird

+3

型に名前を付けるほど簡単ではないことに注意してください。 'type Infinite =(Bool、Infinite)'も禁止されています。あなたはそれを明示的に構築してパターンマッチ(またはアクセサー関数を使用)する必要があるため、エラーの可能性をすべて回避する*データ型*でラップする必要があります。 – ehird