0

これは私の宿題からの質問なので、ヒントをいただければ幸いです。

私は今学期にHaskellstring1を学んでおり、最初の課題では、2 つの文字列 (と ) を入力 し、同じ長さの文字列が作成されるまで、string2最初の文字列の (繰り返される) 文字で構成される文字列を返す関数を作成する必要があります。string1string2

プレリュード機能しか使えないlength

例: asstring1 "Key"と my name"Ahmed"string2関数が返す必要があるものとして取り"KeyKe"ます。

これが私がこれまでに得たものです:

    makeString :: Int -> [a] -> [a]
    makeString val (x:xs)
        | val > 0 = x : makeString (val-1) xs
        | otherwise = x:xs

2 つの文字列を直接指定する代わりに、整数値を指定しています (後で長さを代入できるため) が、これにより実行時エラーが発生します。

*Main> makeString 8 "ahmed"

"ahmed*** Exception: FirstScript.hs: (21,1)-(23,21) : Non-exhaustive patterns in function makeString

リストがなくなって空のリスト(?)になる何かがあるのではないかと思います。

少し助けていただければ幸いです。

4

3 に答える 3

1

カーステンが言ったように、あなたはすべきです

  • リストが空の場合の処理
  • ドロップすると、リストの最後に最初の要素がプッシュされます。
  • n が 0 以下の場合は空のリストを返す

例えば:

makeString :: Int -> [a] -> [a]
makeString _ [] = []    -- makeString 10 "" should return ""
makeString n (x:xs)
    | n > 0 = x:makeString (n-1) (xs++[x])
    | otherwise = []    -- makeString 0 "key" should return ""

ghci でこれを試してください:

>makeString (length "Ahmed") "Key"
"KeyKe"
于 2015-05-19T11:29:54.947 に答える
1

このコードはあなたの問題を解決するのに十分だと思います:

extend :: String -> String -> String
extend src dst = extend' src src (length dst)
    where
        extend' :: String -> String -> Int -> String
        extend' _ _ 0 = []
        extend' [] src size = extend' src src size
        extend' (x:xs) src size  = x : extend' xs src (size - 1)

このextend'関数は、最初の文字列が消費されるまで循環し、その後再び消費を開始します。

takeand cyclelike 関数を使用して作成することもできます。

repeatString :: String -> String
repeatString x = x ++ repeatString x

firstN :: Int -> String -> String
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs

extend :: String -> String -> String
extend src dst = firstN (length dst) (repeatString src)

またはより一般的なバージョン

repeatString :: [a] -> [a]
repeatString x = x ++ repeatString x

firstN :: (Num n, Eq n ) => n -> [a] -> [a]
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs

extend :: [a] -> [b] -> [a]
extend _ [] = error "Empty target"
extend [] _ = error "Empty source"
extend src dst = firstN (length dst) (repeatString src)

任意のタイプのリストを取ることができます:

>extend [1,2,3,4] "foo bar"
[1,2,3,4,1,2,3]
于 2015-05-19T11:19:39.177 に答える
0

注: この回答はリテラシーな Haskellで書かれています。名前を付けて保存しFilename.lhs、GHCi で試してみてください。

この場合、それlength赤ニシンだと思います。これは、再帰とパターン マッチングだけで解決でき、非常に長いリストでも機能します。しかし、まず最初に。

私たちの関数はどの型を持つべきですか? 2 つの弦を取り、最初の弦を何度も繰り返します。これは のように聞こえString -> String -> Stringます。ただし、この「何度も繰り返す」ことは文字列に固有のものではありません。あらゆる種類のリストでこれを行うことができるため、次のタイプを選択します。

> repeatFirst :: [a] -> [b] -> [a]
> repeatFirst as bs = go as bs

わかりました、これまでのところ何も変わったことはありませんよね?で定義repeatFirstしましたがgo、これはまだ不足しています。の項目を の対応する項目とgo交換したいので、基本ケース、つまりが空の場合に何が起こるかは既にわかっています。bsasbs

>    where go  _     []     = []

bs空でない場合はどうなりますか?この場合、 から適切なアイテムを使用したいと考えていますas。したがって、両方を同時にトラバースする必要があります。

>          go (x:xs) (_:ys) = x : go xs ys

現在、次のケースを処理しています: 空の 2 番目の引数リスト、および空でないリスト。空の最初の引数リストを処理する必要があります。

>          go []     ys     = 

この場合、どうすればよいでしょうか?さて、もう一度始める必要がありasます。そして実際、これは機能します:

>                              go as ys

すべてを 1 か所にまとめると、次のようになります。

repeatFirst :: [a] -> [b] -> [a]
repeatFirst as bs = go as bs
   where go  _     []     = []
         go (x:xs) (_:ys) = x : go xs ys
         go []     ys     =     go as ys

制約がない場合は、代わりにcyclezipWith使用できることに注意してください。const

repeatFirst :: [a] -> [b] -> [a]
repeatFirst = zipWith const . cycle

しかし、それはおそらく別の質問です。

于 2016-01-13T21:25:17.313 に答える