2

次の関数は明らかに 2 つのリスト内包表記の間に重複がありますが、コード全体の長さを増やさずに削除するにはどうすればよいでしょうか? ここには素敵な抽象化が潜んでいるような気がしますが、見えません...

letterAt :: [Word] -> Int -> Int -> Maybe Char 
letterAt wrds x y = listToMaybe $ 
  [wtext !! (x - wx) | 
    Word wx wy wtext Across <- wrds, 
    wy == y && x >= wx && x < wx + length wtext] ++ 
  [wtext !! (y - wy) | 
    Word wx wy wtext Down <- wrds, 
    wx == x && y >= wy && y < wy + length wtext] 

背景:

関数は、クロスワード プログラムから取得されます。クロスワードは [Word] で表されます。

data Word = Word { startX :: Int, 
                   startY :: Int, 
                   text :: String, 
                   sense :: Sense } 

data Sense = Across | Down

sense == Across の単語は位置 (startX, startY) から始まり、正の x 方向に続き、sense == Down の単語は正の y 方向に続きます。この関数の目的は、Just 内の (x, y) の位置にある文字を取得することです。文字が存在しない場合は Nothing を取得します。

私がここで犯した Haskell に対する他の罪を自由に指摘してください。私はこの言語を使い始めたばかりで、まだ理解しようとしています!

4

2 に答える 2

4

コードに関するいくつかのポイントを次に示します。

  • filter述語に基づいてリストの特定の要素を選択したい場合に使用することをお勧めします。
  • 特定の述語を満たす最初の要素が必要なだけなので、使用できますData.List.find

条件は対称に見えるので、transform関数を次のように定義できます

transform f x y (Word wx wy wtext Across) = f wtext wy wx y x
transform f x y (Word wx wy wtext Down) = f wtext wx wy x y

コードを書く際に必要な条件は 1 回だけです。

letterAt :: [Word] -> Int -> Int -> Maybe Char
letterAt wrds x y = (transform charValue x y) <$> find (transform condition x y)  wrds
    where
        condition wtext wx wy x y = wx == x && y >= wy && y < wy + length wtext
        charValue wtext wx wy x y = wtext !! (y-wy)
于 2012-09-15T14:38:31.530 に答える
1

Satvik、正しい方向に沿って考えさせてくれたあなたの答えに感謝します。あなたが提案したように条件関数と変換関数を分離した後、関数ではなくデータを変換し、読みやすくするためにすべてをリスト内包表記に戻す方が簡単であることに気付きました。

letterAt :: [Word] -> Int -> Int -> Maybe Char 
letterAt wrds x y = listToMaybe 
  [wtext !! x' | Word wx wy wtext sens <- wrds,   
                 let (x', y') = case sens of 
                       Across -> (x - wx, y - wy) 
                       Down   -> (y - wy, x - wx), 
                 y' == 0, x' >= 0, x' < length wtext ] 

この場合は Data.find を使用する方が良いと指摘されました..これは読みやすさまたは効率のためですか? Haskell ではリストが遅延しているため、リスト内包表記の最初の項目が評価された後に上記のコードが停止するのではないかと推測していますが、これは正しいですか?

于 2012-09-16T04:41:43.547 に答える