Miranda, Amanda, Tina

Amanda is not Tina

Apparently Amanda (the Windows equivalent of Miranda) itself has an equivalent called Tina. Moreover, if my memory is correct, there exists a language combining Java with functional programming features called Pizza. Note: I cannot prove either of these two assertions.

On a less serious note, there are some subtle difference between Miranda (Unix) and Amanda (Windows). It is not possible to simple copy code from one OS to another, although a majority of it should be fine.

Amanda

|| TestStuff.ama

date == (num, num, num)

|| doubleExp
|| given a list of numbers return a list of the whole number components of the square roots of the doubles of those numbers
|| round() would be replaced by entier() in Miranda
doubleExp :: [num] -> [num]
doubleExp [] = []
doubleExp (x:xs) = round( sqrt( (x * 2) ) ) : doubleExp xs


|| prodEven
|| given a list of numbers returns the product of all the even numbers in the list
prodEven :: [num] -> num
prodEven [] = 1
prodEven (x:xs) = x * prodEven(xs), if x mod 2 = 0
                = prodEven(xs), otherwise


|| isDate
|| checks if a date is legal
isDate :: date -> bool
isDate (d, m, y) = okDayAndMonth(d, m) /\ okYear(d,m,y)

okDayAndMonth :: (num, num) -> bool
okDayAndMonth (d, m) = d <= [31,29,31,30,31,30,31,31,30,31,30,31] ! (m-1), if ( m > 0 /\ m <= 12 /\ d > 0)
                     = False, otherwise
                     || do it with the [if otherwise], so that the list is not indexed out of bounds by an invalid day number


okYear :: date -> bool
okYear (d,2,y) = d <= 28, if (y % 4 ~= 0)
               = False, otherwise
okYear anyMonth = True


|| hdr
|| return last item only in the list
hdr :: [*] -> *
hdr [] = error "hdr unexpected empty list"
hdr (x:xs) = xs ! (#xs - 1)

|| tlr
|| return all items in list excluding the last item
tlr :: [*] -> [*]
tlr (x:[]) = []
tlr (x:xs) = x : tlr xs

|| indexr
|| index item in list from end, not start
indexr :: ([*],num) -> *
indexr (x:xs, n) = xs ! (#xs - n-1), if n < #xs  || -1 because miranda indexes from 0
                 = x, otherwise
indexr2 :: ([*],num) -> *            
indexr2 (any, n) = any ! (#any -n)

|| consr, problem with ++, expects a list??
|| append a list to an item
|| consr :: ([*],*) -> [*]
consr (x, any) = any ++ [x]


|| anyUCS, stack recursion
anyUCS :: [*] -> bool
anyUCS [] = False
anyUCS (x:xs) = True, if 'A' <= x /\ x <= 'Z'
              = True, if anyUCS(xs)
              = False, otherwise

|| anyUCA, stack accumulative recursion
anyUCA :: [*] -> bool
anyUCA any = xanyUC (any, False)
              where
              xanyUC (x:xs, status) = xanyUC (xs, isUpper x \/ status)
              xanyUC ([], status) = status
              isUpper c = 'A' <= c /\ c <= 'Z'
              
|| smallestN
|| takes the N smallest numbers from a number list, showing the result in ascending order
smallestN :: (num,[num]) -> [num]
smallestN (n,[]) = []
smallestN (n,x) = getList (x, [])
                    where
                    getList(x, nx)

Miranda

>

Author: Jack Wootton
Last modified: 04/04/05

a typw synonym for a 24 clock

> clock == (num, num, num)

> string == [char]
> stringHours = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"]

isIn returns True if an item exists within a list and False if it doesn't.  Used throughout this file.

> isIn :: ([*],*) -> bool
> isIn ([], anything) = False
> isIn (x:xs, x) = True
> isIn (x:xs, notX) = isIn(xs, notX)


validTime
Check if a time is valid using a 24-hour clock

> validTime :: clock -> bool
> validTime (h,m,s) = okHr h & okMnSc m & okMnSc s
>                      where
>                       okHr h = posOne h & h < 24
>                       okMnSc i = posOne i & i < 60
>                       posOne i = i >= 0 & integer i




timeDiff
Output the number of minutes between any two valid times (ignoring seconds)

> timeDiff :: (num, num, num, num, num, num) -> num
> timeDiff (h, m, s, h1, m1, s1) = ( (h1 - h) * 60) + (m1 - m), if h1 >= h & validTime(h,m,s) & validTime(h1,m1,s1)
>                                = (( (h1 + 24) - h) * 60) + (m1 - m), validTime(h,m,s) & validTime(h1,m1,s1)
>                                = error "timeDiff expects a valid time", otherwise




displayTime
Show a valid time in words to the nearest quarterhour, using a 12-hour display

> displayTime :: clock -> string
> displayTime (h,m,s) = getMins((m*60)+s) ++ stringHours ! ((h-1) mod 12) ++ getAmPm h, if ((m*60)+s) <= 2250
>                     = getMins((m*60)+s) ++ stringHours ! (h mod 12) ++ getAmPm h, otherwise  
>                       where
>                        getMins m = "Quarter to ", if 2250 < m < 3210
>                                  = "Half past ", if 1410 < m <= 2250
>                                  = "Quarter past ", if 450 < m <=1410
>                                  = "", otherwise
>
>                        getAmPm i = " am", if i < 12
>                                  = " pm", otherwise




trebleCube
Given a list of numbers returns a list of those numbers, cubed and then trebled

> trebleCube :: [num] -> [num]
> trebleCube [] = []
> trebleCube (x:xs) = (3 * (x * x * x)) : trebleCube(xs)




prodOdd
Given a list of numbers returns the product of all the odd numbers in the list

> prodOdd :: [num] -> num
> prodOdd [] = 1
> prodOdd (x:xs) =  x * prodOdd(xs), if x mod 2 ~= 0
>                = prodOdd(xs), otherwise




allDifferentS
Evaluates to True if all items in a list are different using stack recursion

> allDifferentS :: [*] -> bool
> allDifferentS [] = True
> allDifferentS (x:xs) = ~ isIn(xs,x) & allDifferentS xs



allDifferentA
Evaluates to True if all items in a list are different using accumulative recursion

> allDifferentA :: [*] -> bool
> allDifferentA [] = True
> allDifferentA (x:xs) = xDifferent(xs, True)
>                        where
>                         xDifferent(x:xs, status) = xDifferent( xs, ~isIn(xs,x) & status)
>                         xDifferent([], status) = status                 


Compare two versions
allDifferentS: Each time the recursive call is made, a computation is postponed and the functiona call gets bigger.  allDifferentS
is the postponed calculation (it must be postponed and put on the stack while the next function call is made).
In stack recursion this means more of the stacks memory is used each time a computation is postponed.
This is inefficient and could cause problems for more processor intensive calculations.
Because logical conjunction is used the possiblity of using lazy evaluation is removed because of this,
the best time growth rate is only O(N).

allDifferentA: Retruns a result after xDifferent has finished its calculations.  The extra function stops the calculation calls
from being stored on the stack as a status value is used to keep a total as the function moves through the list.
Calculations are kept in the status value rather than on the stack, however the entire list is still traversed so the best time
growth is O(N)


separate
Given a list of numbers will return a pair of lists, where the first list contains the even numbers and the second list contains the odd numbers

> separate :: [num] -> ([num],[num])
> separate xs = xseparate ([],[],xs)
>               where
>                xseparate (x,y,[]) = (x,y)
>                xseparate (x,y,a:as) = xseparate(x,y,as), if ~ (integer a) 
>                                     = xseparate(x ++ [a], y, as), if a mod 2 ~= 0
>                                     = xseparate(x, y ++ [a], as), otherwise


smerge
Given two strings, both having standard lexigraphical ordering, will merge them into one string.
If either string is not ordered then an error should be reported

> smerge :: (string, string) -> string
> smerge (x:xs, y:ys) = xsmerge(x:xs, y:ys), if ordered(xs,x) & ordered(ys,y)
>                     = error "smerge expects lexigraphically ordered strings", otherwise
>                       where
>                        ordered ([],a) = True
>                        ordered (x:xs, a) = a <= x & ordered(xs,x)
>
>                        xsmerge([],any) = any
>                        xsmerge(any,[]) = any
>                        xsmerge(x:xs, y:ys) = x : xsmerge(xs,y:ys), if x < y
>                                            = y : xsmerge(x:xs,ys), otherwise


intersect
Given a list of lists produces a list containing one instance of items that appear in all of the lists

> intersect :: [[*]] -> [*]
> intersect [] = []
> intersect x = xintersect x 
>                where
>                 xintersect [] = error "error"
>                 xintersect([]:other) = []
>                 xintersect [other] = other
>                 xintersect(x:xs) = [hd x] ++ xintersect( (tl x) :xs), isInAll (xs, hd x)
>                                  = intersect( (tl x):xs), otherwise
>                                    where
>                                     isInAll([], item) = True
>                                     isInAll(x:xs,item) = isIn(x, item) & isInAll(xs, item)

case analysis = used to check correct and incorrect input for both intersect and xintersect
and that all base cases of these functions were covered.

intersect [] = []
intersect x = xintersect x
xintersect [] = error "error"
xintersect [other] = other
xintersect([]:other) = []

structural induction was used to help design function recursion and started by making use of the
above case analysis.
isInAll([], item) evaluates to true becasue xintersect never passes an empty list to it

structural induction for isIn
isIn ([], anything) = False
isIn (x:xs, x) = True
isIn (x:xs, notX) = isIn(xs, notX)

C/C++ string handling

Returns 1 if string x > string y, -1 if string x < string y, and 0 if they're the same (cse insensitive)

> strcmp :: (string, string) -> num
> strcmp (x,y) = 1, if x > y
>              = -1, if x < y
>              = 0, otherwise


Returns 1 if string x > string y, -1 if string x < string y, and 0 if they're the same (cse sensitive)

> strcasecmp :: (string, string) -> num
> strcasecmp (x,y) = strcmp(lower x, lower y)
>                    where
>                     lower [] = []
>                     lower (x:xs) = decode (code x+32) : lower xs, if 65 <= code x <= 90
>                                  = x : lower xs, otherwise 



Position of first instance of a specified character in a string

> strchr :: (string, char) -> num
> strchr (xs, c) = getPos(xs, c, 0)
>                  where
>                   getPos ([], c, i) = error "cannot find specified char"
>                   getPos(y:ys, c, i) = i+1, if c = y
>                                      = getPos(ys, c, i+1), otherwise



Position of last instance of a specified character in a string

> strrchr :: (string, char) -> num
> strrchr (xs, c) = getRPos(xs, c, #xs)
>                   where
>                    getRPos ([], d, i) = error "cannot find specified char"
>                    getRPos(ys, d, i) = i, if (ys ! (i-1)) = d
>                                      = getRPos(ys, d, i-1), otherwise 



Append a specified number of chars to a string, from another

> strncat :: (string, string, num) -> string
> strncat (s, t, 0) = s
> strncat (xs, y:ys, n) = error "number to large", if n > #(y:ys)
>                       = strncat(xs ++ [y], ys, n-1), otherwise



Create a copy of a string

> strdup :: string -> string
> strdup any = any


Start position of a substring in another string

> strstr :: (string, string) -> num
> strstr (any, []) = error "strstr expects substring of one or more characters"
> strstr any = xstrstr any
>                 where
>                  xstrstr ([],[]) = 1
>                  xstrstr(x, []) = 1
>                  xstrstr([], y) = 0
>                  xstrstr(x:xs, x:ys) = 1, if xstrstr(xs, ys) > 0
>                                      = xstrstr(xs, x:ys) + 1, if xstrstr(xs, x:ys) > 0
>                                      = 0, otherwise
>                  xstrstr(x:xs, any) = xstrstr(xs, any) + 1, if xstrstr(xs, any) > 0
>                                     = 0, otherwise


Miranda does not require any pointers where as any string methods in c would require pointers and c++ would require
either pointers or a class wrapper for string.  All memory functions are hidden from the programmer and therefore
programming time is reduced.  Although a string of characters and a Miranda list of characters is structurely similar
the access methods and built in list methods in Miranda make string operation many times easier.

There is also a danger in c/c++ that the orignal values of the strings may be lost or changed.  In Miranda
the original values are completely safe.

strcmp = would need to derference pointers for each char and also make sure that pointers do not
reference an index position out of a char arrays bounds in c/c++.

Even simple methods such as strdup would require creating a copy of an array of pointers...an ugly task
as the best of times.