2016-05-21 22 views
0

私はF#とHaskellを初めて使っており、もっと時間を割くことを好む言語を決定するためにプロジェクトを実装しています。F#とHaskell(依存型)のベクトルの次元数の型制約

私は、与えられた数値型がトップレベル関数に与えられたパラメータに基づいて(つまり、実行時に)次元を与えられることを期待しています。たとえば、このF#のスニペットでは、私が

type DataStreamItem = LinearAlgebra.Vector<float32> 

type Ball = 
    {R : float32; 
    X : DataStreamItem} 

を持っていると私はタイプDataStreamItemのすべてのインスタンスがD寸法を有することを期待しています。

私の質問は突き止めるために頭痛をすることができ、このような形状mismatche-バグ以来のアルゴリズム開発とデバッグの利益になるが、アルゴリズムがアップして、実行されている場合非問題にする必要があります:

F#またはHaskellのいずれかに、DataStreamItemおよび/またはBallのサイズをDに制限する方法がありますか?あるいは、すべての計算でパターンマッチングに頼る必要がありますか?

後者の場合、そのような制約違反が発生するとすぐにそれを捕捉するための優れた軽量パラダイムが存在します(パフォーマンスが重大な場合には削除できます)。

編集:

Dが拘束されたセンス明確にする:

Dを使用すると、計算グラフとして機能main(DataStream)のアルゴリズムを発現した場合、そのように定義されるが、中間計算の全てmain(DataStream)の実行のためのDの次元に依存する。私は考えることができる最も簡単な例では、DataStreamItemMのドット積のようになります。一週間後

、私は見つける:DataStreamの寸法はM

別編集の寸法パラメータの作成を決定するであろう私はHaskellで依存型で探していたものを正確概説次のブログ:

https://blog.jle.im/entry/practical-dependent-types-in-haskell-1.html

そしてAノート: このredditには、Haskellの従属型に関するいくつかの議論があり、R. Eisenbergのかなり興味深いdissertation proposalへのリンクが含まれています。

+2

最後の質問「どの言語を学習する必要がありますか?それは主に意見に基づいているので、ここではStackOverflowのトピック外の質問の例です。 – chi

+0

@chi私は知っている、私はいくつかの皮肉とそれを書きましたが、多分顔文字は十分に強制的にそれを伝えることはありません。 – user2805751

+0

言語コンテストのアスペクトの問題は別として、あなたが実際に何を求めているかはまだ不明です。実際に 'D'はコンパイル時に固定されていますか? – leftaroundabout

答えて

6

どちらHaskellはF#型システムは、正確に文字列又は「ソート「Nは2〜6ある再帰型TのNネストされたインスタンス」の明示文(直接)に十分に豊富ではありません6 long "となります。その正確な言葉ではなく、少なくとも。

この6文字の長さの文字列型は、type String6 = String6 of char*char*char*char*char*charまたはその一部の変種として表現することができます(技術的には、ベクトルを使用した特定の例では十分です)たとえば、type String6 = s:string{s.Length=6}と言っても意味がありません。さらに重要なことは、concat: String<n> -> String<m> -> String<n+m>という形式の関数を定義することはできません。nmは文字列の長さを表します。

しかし、あなたはこの質問を最初にした人ではありません。。この研究の方向性は存在し、 "dependent types"と呼ばれており、その主旨を「」というより高次でより強力な操作を持つ「」と表現することができます(組合や交差点とは対照的に上記の例では、タイプStringを数値で、他のタイプではなくパラメータ化し、その数値に対して算術演算を行う方法に注意してください。この方向で

最も著名な言語のプロトタイプは、(私の知っていること)AgdaIdrisF*、およびCoq(本当に私の知る限り、完全な取引)です。それらをチェックしてください。しかし、これは明日の終わりのようなものです。これらの言語に基づいた大きなプロジェクトを開始するよう助言しません。

(編集:どうやらあなたcan do certain tricks in Haskell依存型をシミュレートするために、それは非常に便利ではない、とあなたはUndecidableInstancesを有効にする必要が)

また、実行時にチェックを行うことの弱い溶液で行くことができます。一般的な要点は、ベクタ型をプレーンラッパーにラップし、直接的な構築を許可しないでコンストラクタ関数を提供し、それらのコンストラクタ関数が目的のプロパティ(長さ)を確保できるようにします。ような何か:constrained strings:ここ

type Stream4 = private Stream4 of DataStreamItem 
    with 
     static member create (item: DataStreamItem) = 
     if item.Length = 4 then Some (Stream4 item) 
     else None 

     // Alternatively: 
     if item.Length <> 4 then failwith "Expected a 4-long vector." 
     item 

はスコットWlaschinからのアプローチの充実説明です。

+3

"という形式の関数を定義することはできません:' String - > String - > String '" - これは、Haskellでこのようにすることができます。 (しかし私はGHC-8.0がこれをかなり改良すると思います)。 – leftaroundabout

+1

私は、Haskellで従属型を使用することによって失われた保証について知らない。あなたの長さインデックス付き 'String'の例も適切に実行できます。 –

+0

@AndrásKovács私はそれをより正確にするためにその注釈を修正しました。 –

2

正しく理解しても、実際にはどのレベルレベルの算術も行っていないので、“長さのタグ”があります。これは関数呼び出しの連鎖で共有されています。

これはHaskellでこれまで可能でした。私は非常にエレガント考える一つの方法は、所望の長さの標準固定長型を使用して配列に注釈を付けることである:正しい長さを確保するために

newtype FixVect v s = FixVect { getFixVect :: VU.Vector s } 

、あなただけの(多型)を提供スマートコンストラクタこと実際の寸法番号は何も記載されていませんが、固定長タイプ–から完全に安全です!箱なしのタプルから

class VectorSpace v => FiniteDimensional v where 
    asFixVect :: v -> FixVect v (Scalar v) 

instance FiniteDimensional Float where 
    asFixVect s = FixVect $ VU.singleton s 
instance (FiniteDimensional a, FiniteDimensional b, Scalar a ~ Scalar b)  => FiniteDimensional (a,b) where 
    asFixVect (a,b) = case (asFixVect a, asFixVect b) of 
     (FixVect av, FixVect bv) -> FixVect $ av<>bv 

この構造は本当に非効率的である、しかしこれは次元が常に一定であれば、あなたがこのパラダイム–で効率的なプログラムを書くことができるという意味ではありません、あなたは一度だけをラップしてアンラップする必要があると行うことができますランタイムチェックされていないジップ、フォールド、およびLAの組み合わせによるすべての重要な操作。

これにかかわらず、このアプローチは実際には広く使用されていません。実際には、単一の定数ディメンションは、ほとんどの関連する操作にはあまりにも制限があります。タプルを展開する必要がある場合は、非効率的です。最近では、タイプ・レベルの数字で実際にベクトルにタグを付けるという方法があります。このような数字は、GHC-7.4でデータ型を導入することで利用可能な形で利用可能になった。これまでのところ、彼らはやはり扱いにくく、適切な算術演算には適していませんが、今後リリースされる8.0では、Haskellでの依存型プログラミングの多くの面が大幅に改善されます。

効率的な長さインデックス配列を提供するライブラリはlinearです。

+0

私は動的長さの計算があまりにも多くの質問をするだろうと思ったので、私は長さタグを本当に考えていました。しかし、GHC 8.0で動的計算を行うことができるのはとても奨励されています。これらの計算は、計算時間またはコンパイル時間で評価されますか?情報のおかげで。 – user2805751

+0

実際にこのような計算が実行されると言うのは少し難解です - 場合によってはコンパイラがすべてを完全に事前定義してインライン化することができますが、一般的に実行時の算術演算が必要です(ただし、結果)。通常は、計算された次元数を多くのコードで共有することが可能であり、確かに同じコードの多くの_invocations_を使用する必要があります。 – leftaroundabout