September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -1,9 +1,3 @@
on run
map(romanValue, {"MCMXC", "MDCLXVI", "MMVIII"})
--> {1990, 1666, 2008}
end run
-- romanValue :: String -> Int
on romanValue(s)
script roman
@ -18,7 +12,7 @@ on romanValue(s)
-- If this glyph:value pair matches the head of the list
-- return the value and the tail of the list
-- transcribe :: (String, Number) -> Maybe (Number, [String])
on lambda(lstPair)
on |λ|(lstPair)
set lstR to characters of (item 1 of lstPair)
if isPrefixOf(lstR, xs) then
-- Value of this matching glyph, with any remaining glyphs
@ -26,7 +20,7 @@ on romanValue(s)
else
{}
end if
end lambda
end |λ|
end script
if length of xs > 0 then
@ -41,8 +35,40 @@ on romanValue(s)
toArabic(characters of s) of roman
end romanValue
-- TEST -----------------------------------------------------------------------
on run
map(romanValue, {"MCMXC", "MDCLXVI", "MMVIII"})
-- GENERIC LIBRARY FUNCTIONS
--> {1990, 1666, 2008}
end run
-- GENERIC FUNCTIONS ----------------------------------------------------------
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lst to {}
set lng to length of xs
tell mReturn(f)
repeat with i from 1 to lng
set lst to (lst & |λ|(item i of xs, i, xs))
end repeat
end tell
return lst
end concatMap
-- drop :: Int -> a -> a
on drop(n, a)
if n < length of a then
if class of a is text then
text (n + 1) thru -1 of a
else
items (n + 1) thru -1 of a
end if
else
{}
end if
end drop
-- isPrefixOf :: [a] -> [a] -> Bool
on isPrefixOf(xs, ys)
@ -59,54 +85,30 @@ on isPrefixOf(xs, ys)
end if
end isPrefixOf
-- drop :: Int -> a -> a
on drop(n, a)
if n < length of a then
if class of a is text then
text (n + 1) thru -1 of a
else
items (n + 1) thru -1 of a
end if
else
{}
end if
end drop
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
script append
on lambda(a, b)
a & b
end lambda
end script
foldl(append, {}, map(f, xs))
end concatMap
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to lambda(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to lambda(item i of xs, i, xs)
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- uncons :: [a] -> Maybe (a, [a])
on uncons(xs)
if length of xs > 0 then
@ -115,15 +117,3 @@ on uncons(xs)
missing value
end if
end uncons
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property lambda : f
end script
end if
end mReturn

View file

@ -0,0 +1,103 @@
use framework "Foundation"
-- INTEGER VALUE OF ROMAN NUMBER STRING ---------------------------------------
-- fromRoman :: String -> Int
on fromRoman(s)
script subtractIfLower
on |λ|(rn, L)
set {r, n} to rn
if L r then -- Digit values that increase (right to left),
{L, n + L} -- are added
else
{L, n - L} -- Digit values that go down, are subtracted.
end if
end |λ|
end script
snd(foldr(subtractIfLower, {0, 0}, map(my charVal, characters of s)))
end fromRoman
-- charVal :: Char -> Int
on charVal(C)
set V to keyValue({I:1, V:5, X:10, L:50, C:100, D:500, M:1000}, ¬
toUpper(C))
if nothing of V then
0
else
just of V
end if
end charVal
-- TEST -----------------------------------------------------------------------
on run
map(fromRoman, {"MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"})
--> {1666, 1990, 2008, 2016, 2017}
end run
-- GENERIC FUNCTIONS ----------------------------------------------------------
-- foldr :: (a -> b -> a) -> a -> [b] -> a
on foldr(f, startValue, xs)
tell mReturn(f)
set V to startValue
set lng to length of xs
repeat with I from lng to 1 by -1
set V to |λ|(V, item I of xs, I, xs)
end repeat
return V
end tell
end foldr
-- keyValue :: Record -> String -> Maybe String
on keyValue(rec, strKey)
set ca to current application
set V to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
if V is not missing value then
{nothing:false, just:item 1 of ((ca's NSArray's arrayWithObject:V) as list)}
else
{nothing:true}
end if
end keyValue
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with I from 1 to lng
set end of lst to |λ|(item I of xs, I, xs)
end repeat
return lst
end tell
end map
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- snd :: (a, b) -> b
on snd(xs)
if class of xs is list and length of xs = 2 then
item 2 of xs
else
missing value
end if
end snd
-- toUpper :: String -> String
on toUpper(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
uppercaseStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toUpper

View file

@ -0,0 +1 @@
{1666, 1990, 2008, 2016, 2017}

View file

@ -0,0 +1,72 @@
'This code will create a GUI Form and Objects and carry out the Roman Numeral convertion as you type
'The input is case insensitive
'A basic check for invalid charaters is made
hTextBox As TextBox 'To allow the creation of a TextBox
hValueBox As ValueBox 'To allow the creation of a ValueBox
Public Sub Form_Open() 'Form opens..
SetUpForm 'Go to the SetUpForm Routine
hTextBox.text = "MCMXC" 'Put a Roman numeral in the TextBox
End
Public Sub TextBoxInput_Change() 'Each time the TextBox text changes..
Dim cRomanN As Collection = ["M": 1000, "D": 500, "C": 100, "L": 50, "X": 10, "V": 5, "I": 1] 'Collection of nemerals e.g 'M' = 1000
Dim cMinus As Collection = ["IV": -2, "IX": -2, "XL": -20, "XC": - 20, "CD": -200, "CM": -200] 'Collection of the 'one less than' numbers e.g. 'IV' = 4
Dim sClean, sTemp As String 'Various string variables
Dim siCount As Short 'Counter
Dim iTotal As Integer 'Stores the total of the calculation
hTextBox.Text = UCase(hTextBox.Text) 'Make any text in the TextBox upper case
For siCount = 1 To Len(hTextBox.Text) 'Loop through each character in the TextBox
If InStr("MDCLXVI", Mid(hTextBox.Text, siCount, 1)) Then 'If a Roman numeral exists then..
sClean &= Mid(hTextBox.Text, siCount, 1) 'Put it in 'sClean' (Stops input of non Roman numerals)
End If
Next
hTextBox.Text = sClean 'Put the now clean text in the TextBox
For siCount = 1 To Len(hTextBox.Text) 'Loop through each character in the TextBox
iTotal += cRomanN[Mid(hTextBox.Text, siCount, 1)] 'Total up all the characters, note 'IX' will = 11 not 9
Next
For Each sTemp In cMinus 'Loop through each item in the cMinus Collection
If InStr(sClean, cMinus.Key) > 0 Then iTotal += Val(sTemp) 'If a 'Minus' value is in the string e.g. 'IX' which has been calculated at 11 subtract 2 = 9
Next
hValueBox.text = iTotal 'Display the total
End
Public Sub SetUpForm() 'Create the Objects for the Form
Dim hLabel1, hLabel2 As Label 'For 2 Labels
Me.height = 150 'Form Height
Me.Width = 300 'Form Width
Me.Padding = 20 'Form padding (border)
Me.Text = "Roman Numeral converter" 'Text in Form header
Me.Arrangement = Arrange.Vertical 'Form arrangement
hLabel1 = New Label(Me) 'Create a Label
hLabel1.Height = 21 'Label Height
hLabel1.expand = True 'Expand the Label
hLabel1.Text = "Enter a Roman numeral" 'Put text in the Label
hTextBox = New TextBox(Me) As "TextBoxInput" 'Set up a TextBox with an Event Label
hTextBox.Height = 21 'TextBox height
hTextBox.expand = True 'Expand the TextBox
hLabel2 = New Label(Me) 'Create a Label
hLabel2.Height = 21 'Label Height
hLabel2.expand = True 'Expand the Label
hLabel2.Text = "The decimal equivelent is: -" 'Put text in the Label
hValueBox = New ValueBox(Me) 'Create a ValueBox
hValueBox.Height = 21 'ValuBox Height
hValueBox.expand = True 'Expand the ValueBox
hValueBox.ReadOnly = True 'Set ValueBox to Read Only
End

View file

@ -1,16 +1,29 @@
import Data.List (mapAccumL, isPrefixOf)
import Control.Arrow ((***))
romanValue :: String -> Int
romanValue s = sum . snd $ mapAccumL tr s
[("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90) ,("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)]
where
tr s (k, v) =
until (\(s, _) -> not $ isPrefixOf k s)
(\(s, n) -> (drop (length k) s, n + v)) (s, 0)
romanValue =
let tr s (k, v) =
until (not . isPrefixOf k . fst) (drop (length k) *** (v +)) (s, 0)
in sum .
snd .
flip
(mapAccumL tr)
[ ("M", 1000)
, ("CM", 900)
, ("D", 500)
, ("CD", 400)
, ("C", 100)
, ("XC", 90)
, ("L", 50)
, ("XL", 40)
, ("X", 10)
, ("IX", 9)
, ("V", 5)
, ("IV", 4)
, ("I", 1)
]
main :: IO ()
main = mapM_ (putStrLn . show . romanValue)
["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]
main =
mapM_ (print . romanValue) ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]

View file

@ -0,0 +1,12 @@
fromRoman :: String -> Int
fromRoman =
sum .
liftM2 (:) fst snd .
mapAccumR
(\l r ->
( if l <= r
then r
else (-r)
, l))
0 .
fmap charVal

View file

@ -0,0 +1,31 @@
import qualified Data.Map.Strict as M
fromRoman :: String -> Int
fromRoman xs = partialSum + lastDigit
where
(partialSum, lastDigit) = foldl accumulate (0, 0) (evalRomanDigit <$> xs)
accumulate (partial, lastDigit) newDigit
| newDigit <= lastDigit = (partial + lastDigit, newDigit)
| otherwise = (partial - lastDigit, newDigit)
mapRoman :: M.Map Char Int
mapRoman =
M.fromList
[ ('I', 1)
, ('V', 5)
, ('X', 10)
, ('L', 50)
, ('C', 100)
, ('D', 500)
, ('M', 1000)
]
evalRomanDigit :: Char -> Int
evalRomanDigit c =
let mInt = M.lookup c mapRoman
in case mInt of
Just x -> x
_ -> error $ c : " is not a roman digit"
main :: IO ()
main = print $ fromRoman <$> ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]

View file

@ -0,0 +1,13 @@
fromRoman :: String -> Int
fromRoman =
snd .
foldr
(\l (r, n) ->
( l
, (if l >= r
then (+)
else (-))
n
l))
(0, 0) .
fmap evalRomanDigit

View file

@ -0,0 +1,39 @@
import qualified Data.Map.Strict as M (Map, fromList, lookup)
import Data.Maybe (isNothing, isJust, fromJust, catMaybes)
import Data.List (mapAccumL)
mapRoman :: M.Map String Int
mapRoman =
M.fromList
[ ("M", 1000)
, ("CM", 900)
, ("D", 500)
, ("CD", 400)
, ("C", 100)
, ("XC", 90)
, ("L", 50)
, ("XL", 40)
, ("X", 10)
, ("IX", 9)
, ("V", 5)
, ("IV", 4)
, ("I", 1)
]
fromRoman :: String -> Int
fromRoman s =
let value k = M.lookup k mapRoman
in sum . catMaybes . snd $
mapAccumL
(\mi (l, r, i) ->
let mValue = value [l, r] -- mapRoman lookup of [left, right] Chars
(lastPair, pairValue)
| isJust mValue = (Just i, mValue) -- Pair match: index updated
| isNothing mi || i - fromJust mi > 1 = (mi, value [l])
| otherwise = (mi, Nothing) -- Left Char was counted in pair
in (lastPair, pairValue))
Nothing -- Accumulator maybe Index to last matched Char pair
(zip3 s (tail s ++ " ") [0 ..]) -- Indexed character pairs
main :: IO ()
main = print $ fromRoman <$> ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]

View file

@ -1,19 +1,18 @@
var Roman = {
Values: [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400],
['C', 100], ['XC', 90], ['L', 50], ['XL', 40],
['X', 10], ['IX', 9], ['V', 5], ['IV', 4],
['I', 1]],
Values: [['CM', 900], ['CD', 400], ['XC', 90], ['XL', 40], ['IV', 4],
['IX', 9], ['V', 5], ['X', 10], ['L', 50],
['C', 100], ['M', 1000], ['I', 1], ['D', 500]],
UnmappedStr : 'Q',
parse: function(str) {
var result = 0
for (var i=0; i<Roman.Values.length; ++i) {
var pair = Roman.Values[i]
var key = pair[0]
var value = pair[1]
var regex = RegExp('^' + key)
var regex = RegExp(key)
while (str.match(regex)) {
result += value
str = str.replace(regex, '')
str = str.replace(regex, Roman.UnmappedStr)
}
}
return result

View file

@ -0,0 +1,35 @@
(() => {
// romanValue :: String -> Int
const romanValue = s =>
s.length ? (() => {
const parse = [].concat(
...glyphs.map(g => 0 === s.indexOf(g) ? (
[dctTrans[g], s.substr(g.length)]
) : [])
);
return parse[0] + romanValue(parse[1]);
})() : 0;
// dctTrans :: {romanKey: Integer}
const dctTrans = {
M: 1E3,
CM: 900,
D: 500,
CD: 400,
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
IX: 9,
V: 5,
IV: 4,
I: 1
};
// glyphs :: [romanKey]
const glyphs = Object.keys(dctTrans);
// TEST -------------------------------------------------------------------
return ["MCMXC", "MDCLXVI", "MMVIII", "MMMM"].map(romanValue);
})();

View file

@ -0,0 +1 @@
[1990,1666,2008,4000]

View file

@ -0,0 +1,52 @@
(() => {
// Folding from right to left,
// lower leftward characters are subtracted,
// others are added.
// fromRoman :: String -> Int
const fromRoman = s =>
snd(foldr(
([r, n], l) => [l, l >= r ? n + l : n - l], [0, 0],
map(charVal, stringChars(s))
));
// charVal :: Char -> Maybe Int
const charVal = k => {
const v = {
I: 1,
V: 5,
X: 10,
L: 50,
C: 100,
D: 500,
M: 1000
}[k];
return v !== undefined ? v : 0;
};
// GENERIC FUNCTIONS ------------------------------------------------------
// foldr (a -> b -> b) -> b -> [a] -> b
const foldr = (f, a, xs) => xs.reduceRight(f, a);
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// snd :: (a, b) -> b
const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;
// stringChars :: String -> [Char]
const stringChars = s => s.split('');
// show :: a -> String
const show = (...x) =>
JSON.stringify.apply(
null, x.length > 1 ? [x[1], null, x[0]] : x
);
// TEST -------------------------------------------------------------------
return show(
map(fromRoman, ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"])
);
})();

View file

@ -0,0 +1,25 @@
// version 1.0.6
fun romanDecode(roman: String): Int {
if (roman.isEmpty()) return 0
var n = 0
var last = 'O'
for (c in roman) {
when (c) {
'I' -> n += 1
'V' -> if (last == 'I') n += 3 else n += 5
'X' -> if (last == 'I') n += 8 else n += 10
'L' -> if (last == 'X') n += 30 else n += 50
'C' -> if (last == 'X') n += 80 else n += 100
'D' -> if (last == 'C') n += 300 else n += 500
'M' -> if (last == 'C') n += 800 else n += 1000
}
last = c
}
return n
}
fun main(args: Array<String>) {
val romans = arrayOf("I", "III", "IV", "VIII", "XLIX", "CCII", "CDXXXIII", "MCMXC", "MMVIII", "MDCLXVI")
for (roman in romans) println("${roman.padEnd(10)} = ${romanDecode(roman)}")
}

View file

@ -0,0 +1,16 @@
r2a(r)=
n = [1,5,10,50,100,500,1000]
a,m = 0
> i, #.size(r)..1, -1
v,c = n[#.pos("IVXLCDM",#.mid(r,i))]
? v<m, v = -v
? c>m, m = c
a += v
<
<= a
.
t = ["MMXI","MIM","MCMLVI","MDCLXVI","XXCIII","LXXIIX","IIIIX"]
> i, 1..#.size(t,1)
#.output(t[i]," = ",r2a(t[i]))
<

View file

@ -1,9 +1,9 @@
func roman2arabic(roman) {
var arabic = 0;
var last_digit = 1000;
static m = Hash.new(
 
var arabic = 0
var last_digit = 1000
 
static m = Hash(
I => 1,
V => 5,
X => 10,
@ -11,18 +11,18 @@ func roman2arabic(roman) {
C => 100,
D => 500,
M => 1000,
);
roman.uc.split('').map{m{_} \\ 0}.each { |digit|
last_digit < digit && (
arabic -= (2 * last_digit);
);
arabic += (last_digit = digit);
)
 
roman.uc.chars.map{m{_} \\ 0}.each { |digit|
if (last_digit < digit) {
arabic -= (2 * last_digit)
}
arabic += (last_digit = digit)
}
return arabic;
 
return arabic
}
 
%w(MCMXC MMVIII MDCLXVI).each { |roman_digit|
"%-10s == %d\n".printf(roman_digit, roman2arabic(roman_digit));
"%-10s == %d\n".printf(roman_digit, roman2arabic(roman_digit))
}

View file

@ -15,7 +15,7 @@ func roman2arabic(digit) {
:I: '1+',
]).split('+').map{.to_i}.sum;
}
 
%w(MCMXC MMVIII MDCLXVI).each { |roman_num|
say "#{roman_num}\t-> #{roman2arabic(roman_num)}";
}

View file

@ -0,0 +1,45 @@
BEGIN
INTEGER PROCEDURE FROMROMAN(S); TEXT S;
BEGIN
PROCEDURE P(INTVAL, NUM); INTEGER INTVAL; TEXT NUM;
BEGIN
INTEGER NLEN;
NLEN := NUM.LENGTH;
WHILE INDEX + NLEN - 1 <= SLEN AND THEN
S.SUB(INDEX, NLEN) = NUM DO
BEGIN
RESULT := RESULT + INTVAL;
INDEX := INDEX + NLEN;
END WHILE;
END P;
INTEGER RESULT, INDEX, SLEN;
SLEN := S.LENGTH;
INDEX := 1;
P( 1000, "M" );
P( 900, "CM" );
P( 500, "D" );
P( 400, "CD" );
P( 100, "C" );
P( 90, "XC" );
P( 50, "L" );
P( 40, "XL" );
P( 10, "X" );
P( 9, "IX" );
P( 5, "V" );
P( 4, "IV" );
P( 1, "I" );
FROMROMAN := RESULT;
END FROMROMAN;
TEXT T;
FOR T :- "MCMXC", "MMVIII", "MDCLXVI" DO
BEGIN
OUTTEXT("ROMAN """);
OUTTEXT(T);
OUTTEXT(""" => ");
OUTINT(FROMROMAN(T), 0);
OUTIMAGE;
END FOR;
END PROGRAM;

View file

@ -0,0 +1,34 @@
func rtoa( str1: String) -> Int {
var str = str1
var result = 0
for (value, letter) in
[ ( 1000, "M"),
( 900, "CM"),
( 500, "D"),
( 400, "CD"),
( 100, "C"),
( 90, "XC"),
( 50, "L"),
( 40, "XL"),
( 10, "X"),
( 9, "IX"),
( 5, "V"),
( 3, "IIV"),
( 4, "IV"),
( 1, "I")]
{
while str.hasPrefix(letter) {
let first = str.startIndex
let count = letter.characters.count
str.removeSubrange(first ..< str.index(first, offsetBy: count))
result += value
}
}
return result
}
print(rtoa("MDCLXVI")) // 1666

View file

@ -0,0 +1,48 @@
Main:
!------------------------------------------------
! CALLS THE romToDec FUNCTION WITH THE ROMAN
! NUMERALS AND RETURNS ITS DECIMAL EQUIVELENT.
!
PRINT "MCMXC = "; romToDec("MCMXC") !1990
PRINT "MMVIII = "; romToDec("MMVIII") !2008
PRINT "MDCLXVI = "; romToDec("MDCLXVI") !1666
PRINT:PRINT
PRINT "Here are other solutions not from the TASK:"
PRINT "MCMXCIX = "; romToDec("MCMXCIX") !1999
PRINT "XXV = "; romToDec("XXV") !25
PRINT "CMLIV = "; romToDec("CMLIV") !954
PRINT "MMXI = "; romToDec("MMXI") !2011
PRINT:PRINT
PRINT "Without error checking, this also is 2011, but is wrong"
PRINT "MMIIIX = "; romToDec("MMIIIX") !INVAID, 2011
STOP
FUNCTION romToDec(roman AS STRING) AS INTEGER
!------------------------------------------------------
! FUNCTION THAT CONVERTS ANY ROMAN NUMERAL TO A DECIMAL
!
prenum=0!num=0
ln=LEN(roman)
FOR i=ln TO 1 STEP -1
x$=MID(roman,i,1)
n=1000
SELECT CASE x$
CASE "M":n=n/1
CASE "D":n=n/2
CASE "C":n=n/10
CASE "L":n=n/20
CASE "X":n=n/100
CASE "V":n=n/200
CASE "I":n=n/n
CASE ELSE:n=0
END SELECT
IF n < preNum THEN num=num-n ELSE num=num+n
preNum=n
next i
romToDec=num
END FUNCTION

View file

@ -0,0 +1,16 @@
var romans = L(
L("M", 1000), L("CM", 900), L("D", 500), L("CD", 400), L("C", 100),
L("XC", 90), L("L", 50), L("XL", 40), L("X", 10), L("IX", 9),
L("V", 5), L("IV", 4), L("I", 1));
fcn toArabic(romanNumber){ // romanNumber needs to be upper case
if (not RegExp("^[CDILMVX]+$").matches(romanNumber))
throw(Exception.ValueError("Not a Roman number: %s".fmt(romanNumber)));
reg value = 0;
foreach R,N in (romans){
while (0 == romanNumber.find(R)){
value += N;
romanNumber = romanNumber[R.len(),*];
}
}
return(value);
}