Skip to content

Εργαστήριο 1 στη Ηaskell

Εξάσκηση (εκφωνήσεις και λύσεις ασκήσεων)

Άσκηση H1E1 Γράψτε μια συνάρτηση με όνομα volumeBox που να υπολογίζει τον όγκο ενός κουτιού δεχόμενη ως είσοδο το πλάτος, το μήκος και το ύψος του, και μια συνάρτηση με όνομα volumeSquarePyramid που να υπολογίζει τον όγκο μιας πυραμίδας με τετραγωνική βάση δεχόμενη το μήκος της πλευράς της βάσης της πυραμίδας και το ύψος της πυραμίδας. Γράψτε ένα πρόγραμμα σε Haskell που να ζητά από το χρήστη τις διαστάσεις μιας πυραμίδας με τετραγωνική βάση (μήκος πλευράς βάσης και ύψος σε μέτρα) και να υπολογίζει πόσα πέτρινα τούβλα χρειάζονται κατά προσέγγιση για να καλυφθεί ο όγκος της πυραμίδας αν κάθε τούβλο έχει μήκος 19 εκατοστά, πλάτος 9 εκατοστά και ύψος 6 εκατοστά. Δίνεται ότι ο όγκος μιας πυραμίδας είναι ίσος με το ένα τρίτο του γινομένου του εμβαδού της βάσης της πυραμίδας επί το ύψος της.

Λύση άσκησης H1E1

h1e1.hs
import System.IO

main :: IO ()
main = do
  putStr "Μήκος πλευράς βάσης σε μέτρα: "
  hFlush stdout
  input1 <- getLine
  putStr "Ύψος πυραμίδας σε μέτρα: "
  hFlush stdout
  input2 <- getLine
  let nb = read input1 :: Double
      nh = read input2 :: Double
      bricks = volumeSquarePyramid nb nh / volumeBox 0.19 0.09 0.06
  putStrLn ("Αριθμός πέτρινων τούβλων = " ++ show bricks)

volumeBox :: (Num a) => a -> a -> a -> a
volumeBox w h d = w * h * d

volumeSquarePyramid :: (Fractional a) => a -> a -> a
volumeSquarePyramid b h = b * b * h / 3
Μεταγλώττιση και εκτέλεση:
$ ghc h1e1.hs
[1 of 2] Compiling Main             ( h1e1.hs, h1e1.o )
[2 of 2] Linking h1e1
$ ./h1e1
Μήκος πλευράς βάσης σε μέτρα: 10
Ύψος πυραμίδας σε μέτρα: 5
Αριθμός πέτρινων τούβλων = 162443.14489928525

Άσκηση H1E2 Οι αντιστάσεις έχουν έναν χρωματικό κώδικα που υποδεικνύει πόσα Ohms είναι η κάθε μια. Ο κώδικας αποτελείται από τρεις γραμμές και κάθε μία γραμμή υποδηλώνει ένα ψηφίο (black=0, brown=1, red=2, orange=3, yellow=4, green=5, blue=6 violet=7, grey=8, white=9). Η χωρητικότητα σε Ohms υπολογίζεται ως εξής. Η πρώτη γραμμή αντιστοιχεί στο πλέον αριστερό ψηφίο, η δεύτερη γραμμή στο αμέσως επόμενο και η τρίτη γραμμή σε ποσα μηδενικά ακολουθούν. Έτσι, για παράδειγμα ο συνδυασμός violet, grey, red υποδηλώνει 7800 Ohms. Γράψτε ένα πρόγραμμα σε Haskell που για μια αντίσταση ο χρήστης να δίνει τρία χρώματα στη σειρά και το πρόγραμμα να εμφανίζει τα Ohms της αντίστασης.

Λύση άσκησης H1E2

h1e2.hs
import System.IO

main :: IO ()
main = do
  putStrLn "Enter resistor's color code : "
  hFlush stdout
  band1 <- getLine
  band2 <- getLine
  band3 <- getLine
  let c = ohms band1 band2 band3
  putStr ("Ohms = " ++ show c)

-- Συνάρτηση με pattern matching
colorValue :: (Num a) => String -> a
colorValue "black" = 0
colorValue "brown" = 1
colorValue "red" = 2
colorValue "orange" = 3
colorValue "yellow" = 4
colorValue "green" = 5
colorValue "blue" = 6
colorValue "violet" = 7
colorValue "grey" = 8
colorValue "white" = 9
colorValue _ = -1

ohms :: (Num a) => String -> String -> String -> a
ohms band1 band2 band3 = (10 * colorValue band1 + colorValue band2) * 10 ^ colorValue band3
Μεταγλώττιση και εκτέλεση:
$ ghc h1e2.hs
[1 of 2] Compiling Main             ( h1e2.hs, h1e2.o )
[2 of 2] Linking h1e2
$ ./h1e2
Enter resistor's color code :
violet
grey
red
Ohms = 7800

Άσκηση H1E3 Κατασκευάστε μια συνάρτηση με όνομα inRange που να δέχεται τρία ορίσματα min, max και x (ακέραιες τιμές) και να επιστρέφει True ή False ανάλογα με το αν το x βρίσκεται στο διάστημα [min,max] ή όχι. Καλέστε τη συνάρτηση από κύριο πρόγραμμα για 3 τιμές που θα δίνει ο χρήστης και εμφανίστε κατάλληλα μηνύματα. Γράψτε 3 επιπλέον εναλλακτικές υλοποιήσεις της inRange χρησιμοποιώντας let bindings, where και guards.

Λύση άσκησης H1E3

h1e3.hs
import System.IO

main :: IO ()
main = do
  putStr "Enter min : "
  hFlush stdout
  input1 <- getLine
  putStr "Enter max : "
  hFlush stdout
  input2 <- getLine
  putStr "Enter value : "
  hFlush stdout
  input3 <- getLine
  let min = read input1 :: Int
  let max = read input2 :: Int
  let x = read input3 :: Int
  putStrLn "Α' Τρόπος"
  if inRange min max x
    then putStrLn "YES"
    else putStrLn "NO"
  putStrLn "Β' Τρόπος"
  if inRange' min max x
    then putStrLn "YES"
    else putStrLn "NO"
  putStrLn "Γ' Τρόπος"
  if inRange'' min max x
    then putStrLn "YES"
    else putStrLn "NO"
  putStrLn "Δ' Τρόπος"
  if inRange''' min max x
    then putStrLn "YES"
    else putStrLn "NO"

inRange :: (Ord a) => a -> a -> a -> Bool
inRange min max x = min <= x && x <= max

inRange' :: (Ord p) => p -> p -> p -> Bool
inRange' min max x =
  let iub = x <= max
      ilb = x >= min
   in ilb && iub

inRange'' :: (Ord p) => p -> p -> p -> Bool
inRange'' min max x = ilb && iub
  where
    ilb = x >= min
    iub = x <= max

inRange''' :: (Ord a) => a -> a -> a -> Bool
inRange''' min max x
  | x < min = False
  | x > max = False
  | otherwise = True
Μεταγλώττιση και εκτέλεση:
$ ghc h1e3.hs
[1 of 2] Compiling Main             ( h1e3.hs, h1e3.o )
[2 of 2] Linking h1e3
$ ghc h1e3
Enter min : 10
Enter max : 30
Enter value : 20
Α' Τρόπος
YES
Β' Τρόπος
YES
Γ' Τρόπος
YES
Δ' Τρόπος
YES

Άσκηση H1E4 Συμπληρώστε σε ένα αρχείο με όνομα h1e4i.hs τον ακόλουθο κώδικα που ταξινομεί μια λίστα τιμών υλοποιώντας τον αλγόριθμο quicksort.

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
  let smallerSorted = quicksort [a | a <- xs, a <= x]
      biggerSorted = quicksort [a | a <- xs, a > x]
  in  smallerSorted ++ [x] ++ biggerSorted

α) Φορτώστε το αρχείο h1e4i.hs στο ghci και ταξινομήστε τις ακόλουθες λίστες τιμών:

[9, 7, 3, 2, 1, 5, 6, 0, 4, 8]
[3.142, 2.718, 1.414, 1.618]
["Ioannina", "Preveza", "Igoumenitsa", "Arta"]
[False, True, False, True]
Λύση άσκησης H1E4 (α' ερώτημα)
$ ghci h1e4i.hs
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling Main             ( h1e4i.hs, interpreted )
Ok, one module loaded.
ghci> quicksort [9, 7, 3, 2, 1, 5, 6, 0, 4, 8]
[0,1,2,3,4,5,6,7,8,9]
ghci> quicksort [3.142, 2.718, 1.414, 1.618]
[1.414,1.618,2.718,3.142]
ghci> quicksort ["Ioannina", "Preveza", "Igoumenitsa", "Arta"]
["Arta","Igoumenitsa","Ioannina","Preveza"]
ghci> quicksort [False, True, False, True]
[False,False,True,True]
ghci> :module Data.List
ghci> sort [9, 7, 3, 2, 1, 5, 6, 0, 4, 8]
[0,1,2,3,4,5,6,7,8,9]
ghci> :q
Leaving GHCi.

β) Δημιουργήστε ένα αρχείο h1e4.hs που όταν μεταγλωττιστεί με το ghc να προκύπτει εκτελέσιμο που κατά την εκτέλεσή του να ταξινομεί και να εμφανίζει ταξινομημένες τις παραπάνω λίστες.

Λύση άσκησης H1E4 (β' ερώτημα με την υλοποίηση της quicksort)

h1e4.hs
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x : xs) =
  let smallerSorted = quicksort [a | a <- xs, a <= x]
      biggerSorted = quicksort [a | a <- xs, a > x]
   in smallerSorted ++ [x] ++ biggerSorted

main :: IO ()
main = do
  let l1 = [9, 7, 3, 2, 1, 5, 6, 0, 4, 8]
      l2 = [3.142, 2.718, 1.414, 1.618]
      l3 = ["Ioannina", "Preveza", "Igoumenitsa", "Arta"]
      l4 = [False, True, False, True]
  print (quicksort l1)
  print (quicksort l2)
  print (quicksort l3)
  print (quicksort l4)
Μεταγλώττιση και εκτέλεση:
$ ghc h1e4.hs
[1 of 2] Compiling Main             ( h1e4.hs, h1e4.o )
[2 of 2] Linking h1e4
$ ./h1e4
[0,1,2,3,4,5,6,7,8,9]
[1.414,1.618,2.718,3.142]
["Arta","Igoumenitsa","Ioannina","Preveza"]
[False,False,True,True]

Λύση άσκησης H1E4 (β' ερώτημα με τη συνάρτηση βιβλιοθήκης sort)

h1e4sort.hs
import Data.List (sort)

main :: IO ()
main = do
  let l1 = [9, 7, 3, 2, 1, 5, 6, 0, 4, 8]
      l2 = [3.142, 2.718, 1.414, 1.618]
      l3 = ["Ioannina", "Preveza", "Igoumenitsa", "Arta"]
      l4 = [False, True, False, True]
  print (sort l1)
  print (sort l2)
  print (sort l3)
  print (sort l4)
Μεταγλώττιση και εκτέλεση:
$ ghc h1e4sort.hs
[1 of 2] Compiling Main             ( h1e4sort.hs, h1e4sort.o )
[2 of 2] Linking h1e4sort
$ ./h1e4sort
[0,1,2,3,4,5,6,7,8,9]
[1.414,1.618,2.718,3.142]
["Arta","Igoumenitsa","Ioannina","Preveza"]
[False,False,True,True]