Miranda Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Miranda?


Miranda is a lazy, purely functional programming language.


Uses some concepts from ML and Hope.


Miranda has a strong influence on Haskell.


First appeared on 1985.


How to install Miranda?


Miranda can be downloaded from here Downloads

It's available for Windows, Linux, Solaris and Mac.

Miranda doesn't have a REPL, but has an environment which can be customized to use different editors.

For Linux or Windows we can (and we're going to use) Geany.

If you're on Mac follow this Geany OSX.

Who uses Miranda?


Well...it was widely used...


Until Haskell took over...


Miranda was propietary...so that made it harder to maintain its status...


Still, it was widely teached in Universities...


Easier to learn than Haskell...

Starting out...


To begin with...we're going change Miranda's default editor, which is vi.


Open the Miranda enviroment by typing mira on the terminal.


We're going to change the editor to nano, so type /editor nano.

Variables


The are no variables in Miranda...

Wait...what? Where do you store values?

You store them in the app itself...weird, huh?

Type mira and then /e.

				
print :: [char]

print = "Hello World!"
				

Press Ctrl + O to save and then Ctrl + x to exit.

If there's an error you will get a message...otherwise, we're good...

Now, simply type print to call our function.

As we can see Hello World! gets printed on the screen.

In Miranda, characters are strings are not the same...strings are a special type of list...


While there are no variables, we still have data types...


:: helps us to determine the type of something...


				
1977 :: || num


"hello" :: || [char]


'a' :: || char


True :: || bool
				

Strings

Strings are a sequence of characters surrounded by " and of the type [char].

'a' and "a" are not the same.

				
"This is a " ++ "string" || This is a string


"abc" -- "a" || bc


# "abc" || 3


"abc" ! 0 || 'a'


"blink-" ++ shownum(182) || blink-182


"blink-" ++ 123 || type error in expression

                || cannot unify num with [char]
				

Functions

Functions are the most important thing in Miranda...

They are declared as function_name function_parameter = function_body.


				
print :: [char] -> [char]

print name = "Hello " ++ name
				
				
print "Blag"

Hello Blag
				
				
print :: (num,[char]) -> [char]

print(age,name) = "My name is " ++ name ++ 

                  " and I'm " ++ shownum(age) ++ 
                  
                  " year old"
				
				
print(42,"Blag")

My name is Blag and I'm 42 years old
				

List


Lists are the most common and used variable types in Miranda.


As we don't have variables per se...lists are very useful

				
[1,2,3] ++ [4,5,6] || [1,2,3,4,5,6]



hd [1,2,3] || 1



tl [1,2,3] || [2,3]



[1..3] || [1,2,3]



'h' : 'e' : 'l' : 'l' : 'o' : [] || hello
				

First Application


For our First Application we need to wrote the code on any editor. We need to use the .m extension


Then we need to load the file using mira FileName and then simply call our function.


Call your file "triples.m" (all in lowercase).

				
first :: (*,**,***) -> *

first(x,y,z) = x


second :: (*,**,***) -> **

second(x,y,z) = y


third :: (*,**,***) -> ***

third(x,y,z) = z
				

If wonder why we're using "*" instead of a type, that's simply because "*" means...any type -;)

When we run it we're going to see...


Second Application


In this example we're going to use the same function name with different value parameters...


Call your file "greetings.m" (all in lowercase).

				
greet :: ([char],[char]) -> [char]


greet(sex,name) = "Good morning Mr. " ++ name, 

                              if(sex = "male")

                = "Good mornding Ms. " ++ name, 
                
                              if(sex = "female")

                = "Good morning ??? " ++ name, 
                
                              otherwise
				

When we run it we're going to see...


List Comprehensions


I told you...lists are very important -;).


List comprehensions allows us to apply an operation or function to each value of the list.


				
[x * 10 | x <- [1..5]]

#[10,20,30,40,50]



[x * 10 | x <- [1..10]; x * 10 > 50]

#[60,70,80,90,100]



||This section should go on

||default Miranda app using /e
				
				
||This section can be called after editing

||the default Miranda app


double :: num -> num

double num = num * 2



[double x | x <- [1..10]]

#[2,4,6,8,10,12,14,16,18,20]
				

Recursion


Recursion is one of the key points in Miranda...you call a function that calls itself multiple times.


We can pass different values as parameters, and it that way we can alter the value of the app


Also, we can use something called "Pattern Matching" which is used to determine which function to call...


Third Application


In this example we're going to create a Fibonacci sequence generator...


Call your file "fibonacci.m" (all in lowercase).


				
fib :: (num, num, num) ->  [char]

fib(num,a,b) = show(a+b) ++ " " ++ 

               fib((num - 1),(a+b),a), if(a > 0 & num > 1)

             = show(a) ++ " " ++ show(b) ++ 
             
               " " ++ show(a+b) ++ " " ++ 
               
               fib((num - 1),(a+b),b), if(a == 0)

             = [], otherwise



showFib :: num -> [char]

showFib num = "\n" ++  fib(num, 0, 1) ++ "\n"    
				

When we run it we're going to see...


Fourth Application


In this example we're going to create an LED Number


Call your file "led.m" (all in lowercase).


				
showLED :: num -> [char]

showLED num = getLED(digits(shownum(num),0))



layno :: [[char]] -> [char]

layno [] = []

layno(a:x) = a ++ layno x



getLED :: [num] -> [char]

getLED(nums) = layno [make_led_digit(x,1) | x <- nums] ++ 

               "\n" ++

               layno [make_led_digit(x,2) | x <- nums] ++ 
               
               "\n" ++

               layno [make_led_digit(x,3) | x <- nums] ++ 
               
               "\n"
				
				
digits :: ([char],num) -> [num]

digits(text,num) = (numval((text ! num) : "") : []) ++ 

                    digits(text,(num + 1)), 
                    
                    if (num < # text - 1)

digits(text,num) = (numval((text ! num) : "") : []), 

                    if (num < # text)



make_led_digit :: (num,num) -> [char]

make_led_digit(0,1) = " _  "

make_led_digit(0,2) = "| | "

make_led_digit(0,3) = "|_| "

make_led_digit(1,1) = "  "

make_led_digit(1,2) = "| "   

make_led_digit(1,3) = "| "
				
				
make_led_digit(2,1) = " _  " 

make_led_digit(2,2) = " _| " 

make_led_digit(2,3) = "|_  "

make_led_digit(3,1) = "_  "

make_led_digit(3,2) = "_| "  

make_led_digit(3,3) = "_| "

make_led_digit(4,1) = "    " 

make_led_digit(4,2) = "|_| " 

make_led_digit(4,3) = "  | "

make_led_digit(5,1) = " _  " 

make_led_digit(5,2) = "|_  " 

make_led_digit(5,3) = " _| "
				
				
make_led_digit(6,1) = " _  " 

make_led_digit(6,2) = "|_  " 

make_led_digit(6,3) = "|_| "

make_led_digit(7,1) = "_   " 

make_led_digit(7,2) = " |  " 

make_led_digit(7,3) = " |  "

make_led_digit(8,1) = " _  "

make_led_digit(8,2) = "|_| " 

make_led_digit(8,3) = "|_| "

make_led_digit(9,1) = " _  " 

make_led_digit(9,2) = "|_| " 

make_led_digit(9,3) = " _| "
				

When we run it we're going to see...


Fifth Application


In this example we're going to create a Decimals to Romans application


Call your file "dectoromans.m" (all in lowercase).


				
showRomans :: num -> [char]

showRomans num = "\n" ++ layx(get_roman(num,0))



layx :: [[char]] -> [char]

layx [] = []

layx(a:x) = a ++ layx x



get_roman :: (num, num) -> [[char]]

get_roman(num,ctr) = make_roman(roman_keys ! ctr) ++ 

                     get_roman(num - (roman_keys ! ctr), 
                     
                     ctr), if(num >= (roman_keys ! ctr))

get_roman(num,ctr) = get_roman(num, ctr + 1), 

                     if(num < (roman_keys ! ctr) & 
                     
                     num > 0)
				
				
get_roman(num,ctr) = ["\n"], if(num <= 0)



make_roman :: num -> [[char]]

make_roman(1) = ["I"]; make_roman(4) = ["IV"]; 

make_roman(5) = ["V"]; make_roman(9) = ["IX"]; 

make_roman(10) = ["X"]; make_roman(40) = ["XL"];

make_roman(50) = ["L"]; make_roman(90) = ["XC"]; 

make_roman(100) = ["C"]; make_roman(400) = ["CD"]; 

make_roman(500) = ["D"]; make_roman(900) = ["CM"];

make_roman(1000) = ["M"]



roman_keys :: [num]

roman_keys = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
				

When we run it we're going to see...


Sixth Application


In this example we're going to read a file and count how many time a letter appears...


Call your file "countletters.m" (all in lowercase).


Create a file called "readme.txt" with the following text...


"This is a text file that we're going to read using Miranda"


				
readFile :: [char]

readFile = read "readme.txt"


getLetter :: ([char], num) -> char

getLetter (list, counter) = list ! counter 


countLetters :: (char,[[char]],num,num,num) -> [char]

countLetters(letter,list,top,counter,count) 

= countLetters(letter,list,top,counter + 1, count + 1), 

  if(letter = ((list ! 0) ! counter) & counter < top)

= countLetters(letter,list,top,counter + 1, count), 

  if(letter ~= ((list ! 0) ! counter) & counter < top)

= (letter : "") ++ " --> " ++ shownum(count), otherwise
				
				
print :: ([char]) -> [char]

print(file) = "\n" ++ countLetters(file ! 0,[file],

              # file - 1,0,0) ++ print(remove(file,
              
              [file ! 0],0)), if(# file > 1)
              
print(file) = "", if(# file <= 0)

            = "", otherwise


main :: [char]

main = print(readFile)
				
				
remove :: ([char], [char], num) -> [char]

remove(file,letter,counter) = remove((file -- letter),

                              letter,counter + 1), 
                              
                              if(counter < # file - 1)
                              
                              
remove(file,letter,counter) = file, if(counter > # file)
                            
                            = file, otherwise
				

When we run it we're going to see...


That's it for now...


I hope you had some fun...


Functional languages are very important


because they force you think differently...


Miranda documentation is not exactly abudant...


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...