1

重複の可能性:
haskellで文字列を反復処理し、単一の文字を部分文字列に置き換えます

文字列([Chars])を調べ、この文字を別の文字列に置き換える必要があるかどうかをすべての文字でチェックする関数を実装しようとしています。たとえば、「XYF」と「X = HYHY」、「Y = OO」というルールで構成される[Chars]がある場合、出力は「HYHYOOF」になります。

私が定義した次の2つのタイプを使用したいと思います。

type Letters = [Char]
data Rule = Rule Char Letters deriving Show

私の考えでは、ガードを使用すると、関数は次のようになります。ただし、問題は、すべてのルールを参照して、現在の文字xに適合するルールがあるかどうかを確認するときに、再帰呼び出しがどのように表示されるかについての情報が見つからないことです。表記がどうなるかについて、誰かがヒントを教えてくれることを願っています。

apply :: Letters -> [Rule] -> Letters
apply _ _ = []
apply (x:xs) (Rule t r:rs)  
| x /= t = apply x (Rule t rs)
| x == t = r++rs:x
| otherwise  = 
4

3 に答える 3

5

ルールが一致するかどうかをチェックするヘルパー関数を提案します。

matches :: Char -> Rule -> Bool
matches c (Rule x _) = c == x

次に、各文字について、一致するルールがあるかどうかを確認します

apply :: Letters -> [Rule] -> Letters
apply [] _ = []
apply s [] = s
apply (c:cs) rules = case filter (matches c) rules of
                       [] -> c : apply cs rules
                       (Rule _ rs : _) -> rs ++ apply cs rules

rules内で明示的な再帰を試みると、apply後の文字を置き換えるための完全なルールリストを覚えておく必要があるため、醜くなりすぎます。

于 2012-10-19T13:10:01.493 に答える
2

一般的なユーティリティ関数を使用してこれを行う方法を学ぶことをお勧めします。ここで必要な2つの主要な機能:

  1. lookup :: Eq a => a -> [(a, b)] -> Maybe b。連想リスト(マップまたは辞書を表すために使用されるペアのリスト)でマッピングを検索します。
  2. concatMap :: (a -> [b]) -> [a] -> [b]。これはに似てmapいますが、リストにマップされた関数はリストを返し、結果は連結されます(concatMap = concat . map)。

使用するには、タイプを次のより一般的な同義語lookupに変更する必要があります。Rule

type Rule = (Char, String)

Stringこれはの同義語であることも忘れないでください[Char]。これはconcatMap、に適用するとString、各文字が文字列に置き換えられることを意味します。これで、例を次のように書くことができます(引数の順序を変更しました)。

apply :: [Rule] -> String -> String
apply rules = concatMap (applyChar rules) 

-- | Apply the first matching rule to the character.
applyChar :: [Rule] -> Char -> String
applyChar rules c = case lookup c rules of
                      Nothing -> [c]
                      Just str -> str

-- EXAMPLE
rules = [ ('X', "HYHY")
        , ('Y', "OO") ]

example = apply rules "XYF"  -- evaluates to "HYHYOOF"

引数の型が結果と同じである場合、その引数を最後の引数にすることが役立つことが多いため、引数の順序を変更しましたapply(関数のチェーンが容易になります)。

モジュール(= 、= )の効用関数fromMaybe :: a -> Maybe a -> aを使用して、さらに進んでこれをワンライナーに変えることができます。Data.MaybefromMaybe default NothingdefaultfromMaybe default (Just x)x

import Data.Maybe

apply rules = concatMap (\c -> fromMaybe [c] $ lookup c rules)

これを補完するために実行できる演習は、これらすべてのユーティリティ関数のバージョンを自分で手動で作成することです。lookup、 (およびconcatMapに分解します)、および。そうすれば、このソリューションに含まれる「フルスタック」を理解できます。concat :: [[a]] -> [a]map :: (a -> b) -> [a] -> [b]fromMaybe

于 2012-10-19T18:44:34.530 に答える
1

私のソリューションは他のソリューションと構造的に似ていますが、モナドを使用しています。

import Control.Monad 
import Data.Functor 
import Data.Maybe 

match :: Char -> Rule -> Maybe Letters
match c (Rule c' cs) = cs <$ guard (c == c')

apply :: Letters -> [Rule] -> Letters
apply cs rules = 
  [s | c <- cs
     , s <- fromMaybe [c] $ msum $ map (match c) rules]    

私たちが扱っている最初のモナドはですMaybe a。それは実際にはもう少し、MonadPlus私たちが使用できるようにする(ここでは最初の「ヒット」のmsumようなものを要約します)。[Nothing, Just 2, Nothing, Just 3]Just 2

2番目のモナドはです[a]。これにより、でリスト内包表記を使用できますapply

于 2012-10-19T22:15:00.337 に答える