2012-04-21 14 views
4

は、私はこのような愚かな何かを持っていると言う:ハスケルの場合の短い構文?

data SomeType 
    = Unary Int 
    | Associative SomeType 
    | Binary SomeType SomeType 

some_func :: SomeType -> Int 
some_func s = 
    case s of 
     Unary n -> n 
     Associative s1 -> some_func s1 
     Binary s1 s2 -> some_func s1 + some_func s2 

ここsome_funcが与えられたSomeType内のすべてのSomeTypesに目を通すと、すべての単項データコンストラクタのint型を合計します。 SomeTypeは再帰的なデータ型です。

これらのパターンの一致では、私はsome_func s1を繰り返しています。 @、いつ、何か他のものを使用してsf1 = some_func s1を宣言し、両方で使用する方法はありますか?このような何か:

data SomeType 
    = Unary Int 
    | Associative SomeType 
    | Binary SomeType SomeType 

some_func :: SomeType -> Int 
some_func s = 
    case s of 
     Unary n -> n 
     Associative s1 -> sf1 
     Binary s1 s2 -> sf1 + sf2 
     where 
      sf1 = some_func s1 
      sf2 = some_func s2 

ここでの問題は、S1とS2のみ->後のブロックで知られており、SF1を計算することができないということです。

+0

s1とs2とは何ですか、私はその定義を見ることができません。あなたはsをパラメタとして得て、sf1とsf2だけを定義します。 –

+1

s1とs2はSomeTypeのもので、ケースのパターン一致のものです –

答えて

5

不正使用記録の構文!同じタイプの異なるコンストラクタは同じ名前のフィールドを自分の記録にを持つことが許されていることを

data SomeType 
    = Unary { u :: Int } 
    | Associative { s1 :: SomeType } 
    | Binary { s1, s2 :: SomeType } 

someFunc :: SomeType -> Int 
someFunc s = case s of 
    Unary{}  -> u s 
    Associative{} -> sf1 
    Binary{}  -> sf1 + sf2 
    where 
    sf1 = someFunc (s1 s) 
    sf2 = someFunc (s2 s) 

注意。怠惰は、Associativeブランチを下った場合、sf2のエラーを防止します。

+1

私はこれが最もシンプルで洗練されたソリューションだと思います。 –

5

答えはいいえです。s1Associativeで、s1Binaryとは異なります。彼らが同じ名前を持っているという事実は、異なった文脈の中に存在するため、注意散漫です。

私はあなたがヘルパーを使用して、いくつかのタイピングを救うことができるが、これは本当に繰り返しロジックカプセル化を支援しないと思います。私は、これは、この特定のケースでは、それは短く作ってあげるかどうかわからないんだけど

some_func :: SomeType -> Int 
some_func s = go s 
    where go (Unary n) = n 
     go (Associative s1) = go s1 
     go (Binary s1 s2) = go s1 + go s2 
+0

ダーン、情報ありがとう! –

+0

'some_func s = go s' - ' go'という言葉でこれを書くのは目的がありません。ちょうど 'some_func'レベルで直接パターンマッチングするのではないのですか?これは「いくつかの入力を省く」ためにのみ提案されていましたか?私はいくつかのキーストロークを保存しても、値を追加しないヘルパー関数を使用しないことをお勧めします。 –

+0

ダンバートン、 "私は思います"とは非常に気にしませんでした。私はそれがほぼ完全に無意味であることに同意する。 – huon

4

をより一般的なケースでは、Scrap Your Boilerplateをチェックアウトする必要があります。例えば: - SYBは、すべての再帰の面倒を見ることができるよう

{-# LANGUAGE Rank2Types, DeriveDataTypeable, NoMonomorphismRestriction #-} 

import Data.Generics 

data SomeType 
    = Unary Int 
    | Associative SomeType 
    | Binary SomeType SomeType 
    deriving (Data, Typeable, Show) 

flatten_sometype [email protected](Unary _) = x 
flatten_sometype (Associative s) = s 
flatten_sometype (Binary (Unary a) (Unary b)) = Unary $ a + b 

some_func2 = let Unary n = everywhere (mkT flatten_sometype) 
      in n 

は、everywhereを使用することによって、私は地元の変換を指定する必要があります。これが本当に役に立つのは、複数のタイプが関係しているときです。 SYBはあなたがであることを喜んでトンネリングするタイプで、でもありません。どれくらい使っているかには注意してください。過剰に使用された場合、GCチャーンが発生する可能性があります。

+0

flatten_sometypeの型シグネチャは何ですか? –

+0

@AramKocharyan: 'SomeType→SomeType'。しかし、それは完全な機能ではありません。 – Vitus

+0

'some_func2'の型も' SomeType-> SomeType'ですよね?元の 'some_func'は' SomeType - > Int'でした。私はそれを 'Unary'コンストラクタに入れたいのですか? –

7

これは質問に答えていないが、問題を解決する可能性があります:それを書くために

{-# LANGUAGE DeriveFoldable #-} 
module SomeType where 
import Data.Foldable as F 

data SomeType a 
    = Unary a 
    | Associative (SomeType a) 
    | Binary (SomeType a) (SomeType a) 
     deriving (Foldable) 

some_func :: SomeType Int -> Int 
some_func = F.foldl1 (+) 
0

最短の方法は、単にパターンマッチングする必要があります:

some_func :: SomeType -> Int 
some_func (Unary n) = n 
some_func (Associative s) = some_func s 
some_func (Binary s1 s2) = (some_func s1) + (some_func s2) 

枚の繰り返しがまだありますあなたの質問にはおそらく答えません... some_funcfmap some_funcの形で定義することを含む何か?

関連する問題