1votos

Numeros Romanos en Haskell en Haskell

por josejuan hace 3 años

Este desafío está repetido, pero como no lo había resuelto ahí va.

Resolver las cuestiones planteadas en el lenguaje de programación haskell (Al tener varias reglas a cumplir y debido a que es mucho texto el planteamiento lo coloque en dificultad difícil, sin embargo su realización no lo es, es solo porque es algo largo el comprenderlo)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
{-# LANGUAGE OverloadedStrings #-} 
import Data.String 
import Data.Maybe 
import Data.List 
import Data.Function 
import Control.Applicative 
import Test.QuickCheck 
 
data R = I | V | X | L | C | D | M deriving (Eq, Ord, Read, Show) 
newtype Roman = Roman { un :: [R] } 
 
-- Podremos escribir en código literales como "MCI" y realmente serán `Roman` (no cadenas) 
instance IsString Roman where fromString = Roman . map (read . (:[])) 
instance Show Roman     where show = concatMap show . un 
 
-- La forma correcta no admite resta de resta (ej. IXL para dar 41, debe ser XLI) 
romanToInt :: Roman -> Maybe Int 
romanToInt = add . map (\rs@(r:_) -> (value r * length rs, r)) . group . un 
    where value r = snd $ head $ filter ((r==).fst) [(M,1000),(D,500),(C,100),(L,50),(X,10),(V,5),(I,1)] 
          add [ ] = Just 0 
          add [x] = Just $ fst x 
          add (x:y:rs) | snd x < snd y = ((fst y - fst x) +) <$> add    rs 
                       | otherwise     = ((fst x        ) +) <$> add (y:rs) 
 
-- Existen reglas de conversión, usamos un mapa `m` 
intToRoman :: Int -> Roman 
intToRoman = Roman . p 
    where p 0 = [] 
          p n = q ++ p (n - z) where ((q, z):_) = filter ((n>=).snd) m 
          m = [([M],1000),([C,M],900),([D],500),([C,D],400),([C],100),([X,C],90),([L],50) 
              ,([X,L],40),([X],10),([I,X],9),([V],5),([I,V],4),([I,I,I],3),([I,I],2),([I],1)] 
 
-- Ya está. 
 
 
 
 
 
 
 
 
 
 
 
-- Tests (de wikipedia) 
examples :: [(Roman, Int)] 
examples = [("XLV",45),("CDL",450),("IV",4),("IX",9),("XL",40),("XC",90),("CD",400) 
           ,("CM",900),("XIX",19),("CXC",190),("MCM",1900),("XV",15),("CL",150),("MD",1500) 
           ,("V",5),("L",50),("D",500),("III",3),("XXX",30),("CCC",300),("XCIX",99) 
           ,("CMXCIX",999),("CDXC",490),("CMXC",990),("XLI",41),("XXXIX",39) 
           ,("CDX",410),("CCCXC",390)] 
 
main = do 
 
    -- Lanzamos los tests de wikipedia 
    mapM_ (\(r, d) -> putStrLn $ show r ++ " => " ++ show ((==d) <$> romanToInt r)) examples 
     
    -- Verificamos automáticamente el invariante `toInt . fromInt == id` 
    quickCheckWith (stdArgs { maxSuccess = 10000 }) (\n -> let w = 1 + abs n in w == (fromJust.romanToInt.intToRoman) w) 
 
{- 
    XLV => Just True 
    CDL => Just True 
    IV => Just True 
    IX => Just True 
    XL => Just True 
    XC => Just True 
    CD => Just True 
    CM => Just True 
    XIX => Just True 
    CXC => Just True 
    MCM => Just True 
    XV => Just True 
    CL => Just True 
    MD => Just True 
    V => Just True 
    L => Just True 
    D => Just True 
    III => Just True 
    XXX => Just True 
    CCC => Just True 
    XCIX => Just True 
    CMXCIX => Just True 
    CDXC => Just True 
    CMXC => Just True 
    XLI => Just True 
    XXXIX => Just True 
    CDX => Just True 
    CCCXC => Just True 
    +++ OK, passed 10000 tests. 
-} 
1 comentario
0votos

Escrito por Pedro Romero hace 3 años

Excelente!!! SOLUCIONADO
En verdad que es una solución muy buena y buen detalle al agregarle la función para convertir de enteros a romanos.

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.