1

というわけで、問題シート用のこの興味深い実践演習を用意しました。整数 (5000 未満) をローマ数字に変換します。これが私が書いたコードです。ただし、スクリプトを GHCI にロードするのに苦労しています (入力 `=' の解析エラー)。何か案は?

units, tens, hundreds, thousands :: [String]
units=["I", "II", "III", "IV", "V", "VI", "VII", "IIX", "IX"]
tens=["X", "XX", "XXX", "XL", "L", "LX", "LXX", "XXC", "XC"]
hundreds=["C", "CC", "CCC", "CD", "D", "DC", "DCC", "CCM","CM"]
thousands=["M", "MM", "MMM", "MV", "V"]

combine :: (Int,Int,Int,Int) -> String
combine (0,0,0,u)   = units !! u
combine (0,0,t+1,0) = tens !! t
combine (0,0,t+1,u) = tens !! t ++ units !! u
combine (0,h+1,0,0) = hundreds !! h
combine (0,h+1,t+1,0) = hundreds !! h ++ tens !! t
combine (0,h+1,t+1,u)   = hundreds !! h ++ tens !! t ++ units !! u
combine (f+1,0,0,0) = thousands !! f
combine (f+1,h+1,0,0)   = thousands !! f ++ hundreds !! h
combine (f+1,h+1,t+1,0) = thousands !! f ++ hundreds !! h ++ tens !! t
combine (f+1,h+1,t+1,u) = thousands !! f ++ hundreds !! h ++ tens !! t ++ units !! u
4

3 に答える 3

2

実際、このプログラムにはいくつかの構文エラーがあります (編集: @Lukasz の編集のおかげで、構文エラーは 1 つだけになりました)。しかし、あなたが求めているのは、 でバインディングを作成できないという事実が原因ですghci。プログラムのどこに書くか

a = 1

ghciあなたは書く必要があります

let a = 1

そうしないと、parse error on input `='エラーが発生します。

sを挿入する代わりに、プログラムをファイルに入れてコンパイルghcまたは実行することをお勧めします。これにより、将来の作業とバグ修正がより便利になります。runhaskelllet

于 2013-10-30T12:07:55.210 に答える
0

整数とローマ数字の間の変換を処理するモジュールを作成しました。ただし、私のモジュールには 3 つの欠点があります。

  1. 私のモジュールが処理できるローマ数字の最大値は 4999 を超えません。これは、ローマ数字の最大単位は「M」であり、「MMMM」は規則によって有効なローマ数字ではないと想定したためです。

  2. applicative、functor、monad を十分に習得していなかったので、予期しないキーを避けるために関数 "findKey" で Maybe を使用しませんでした。

  3. ローマ数字の文字列で「VIV」、「LXL」、「DCD」の組み合わせを探し、それらを「IX」、「XC」、「CM」に置き換える、prettyRoman2 を終了する方法がわかりません。それぞれ。

     module Roman 
    ( roman2Dec
     , dec2Roman
    ) where
    
    import Data.List (isInfixOf)
    
    -- The max number the program can deal with will not exceed than 4999
    
    romanUnits :: [(Char, Int)]
    romanUnits = [('I', 1), ('V', 5), ('X', 10), ('L', 50), ('C', 100), ('D', 500), ('M', 1000)]
    
    romanDividers :: [Int]
    romanDividers = reverse $ map snd romanUnits
    
    romanDigits :: [Char]
    romanDigits  = reverse $ map fst romanUnits
    
    -- short divide n by each of those in dividers
    shortDivide :: Int -> [Int] -> [Int]
    shortDivide n [] = []
    shortDivide n dividers = let (quotient, remainder) = n `divMod` (head dividers)
                             in quotient : shortDivide remainder (tail dividers)
    
    dec2Roman :: Int -> String
    dec2Roman n = concat $ map prettyRoman1 (zipWith (\x y -> replicate x y) (shortDivide n romanDividers) romanDigits)
    
    prettyRoman1 :: String -> String
    prettyRoman1 roman
      | roman == "IIII" = "IV"
      | roman == "XXXX" = "XL"
      | roman == "CCCC" = "CD"
      | otherwise = roman
    
    -- prettyRoman2: Replace VIV, LXL, DCD with IX, XC, and CM respectively. 
    -- After that, the dec2Roman will be modifed as dec2Roman' = prettyRoman2 dec2Roman
    prettyRoman2 :: String -> String
    prettyRoman2 = undefined
    
    findKey :: Eq a => a -> [(a, b)] -> b
    findKey key = snd . head . filter (\(k, v) -> k == key)
    
    romanValue :: Char -> Int
    romanValue c = findKey c romanUnits
    
    roman2Dec :: String -> Int
    roman2Dec [] = 0
    roman2Dec [x] = romanValue x
    roman2Dec (x:y:xs)
      | romanValue x < romanValue y  = (-1) * romanValue x  + roman2Dec (y:xs)
      | otherwise = romanValue x + roman2Dec (y:xs)
    
于 2016-08-02T15:52:19.207 に答える