Εργαστήριο Τεχνολογίας Λογισμικού
0 votes
252 views

Καλησπέρα, θα ήθελα να γνωρίζω πώς μπορώ να κάνω pattern matching με μια local μεταβλητή (ή "εξωτερικότερα" ορισμένη), αν γίνεται. Μάλλον μπορώ να πετύχω αυτό που θέλω προσθέτοντας μια ακόμα παράμετρο, αλλά σε συναρτήσεις που έχουν ήδη πολλές χάνεται λίγο η μπάλα και φαίνεται άσχημο.

Τα δύο πρώτα snippets δεν δουλεύουν, συγκεκριμένα βγάζουν redundancy error (άρα η ML θεωρεί το 'Μ' ως μια τυχαία μεταβλητή και δεν την κάνει bind με το 5). Στο μάθημα είχαμε πει ότι το if () then () else() είναι ουσιαστικά ένα case. Εδώ όμως φαίνεται να μην αληθεύει αυτό, γιατί το τελευταίο snippet γίνεται compile και δουλεύει κανονικά.

   (* doesn't work:
    local
      val M = 5
    in
      fun isit5 M = true
        | isit5 _ = false
    end
    *)
    
    (* doesn't work:
    local
      val M = 5
    in
      fun isit5 n =
          case n of
              M => true
              | _ => false
    end
    *)
    
    (*works*)
    local
      val M = 5
    in
      fun isit5 n =
          if(n = M) then true else false
    end
in pl1 by (270 points)
retagged by | 252 views

1 Answer

+1 vote
Best answer

Το if ... then ... else ... είναι ένα case αλλά όχι το case που λες εδώ. Συγκεκριμένα το παρακάτω case:

case <booleanExpr> of 
  true   => <expr1>
  false  => <expr2>

είναι ισοδύναμο με το παρακάτω if:

if <booleanExpr> then <expr1> else <expr2>

Στην περίπτωση που έχεις εδώ το αντίστοιχο case είναι:

local
  val M = 5
in
  fun isit5 n =
    case n = M of
        true  => true
        false => false
end

Στο pattern matching όντως αυτό που γίνεται είναι ότι το M μέσα στην isit5 θα γίνει bound με την τιμή του n (και άρα το _ είναι redundant). Αυτή είναι και μία από τις δουλειές του pattern matching (να κάνει δηλαδή destructuring και bind σε φρέσκες μεταβλητές). Γενικά δεν νομίζω οτι μπορείς μέσα σε pattern να χρησιμοποιήσεις προηγούμενη μεταβλητή, γιατί αλλιώς χάνεις την παραπάνω λειτουργικότητα.

Αυτό που θες εσύ να κάνεις μπορεί να υλοποιηθεί με κάποιο test ισότητας, όπως κάνεις και με το if then else. Η συγκεκριμένη συνάρτηση βέβαια μπορεί να υλοποιηθεί και πιο μινιμαλιστικά ως εξής:

local
  val M = 5
in
  fun isit5 n = n=M
end

αλλά δεν ξέρω αν αυτό είναι κάτι που σε ενδιαφέρει.

by (1.1k points)
selected by
0

Ευχαριστώ! Κάτι άλλο (σχετικό με pattern matching):

fun foo arg n - 1 n = <expr1>
  | foo arg n - 2 n = <expr2>
  | foo arg n - 3 n = <expr3>
  | foo arg _ _= <expr4>

Κάτι σαν το παραπάνω θα μπορούσα να το υλοποιήσω μόνο με nested ifs;

+1

Το συγκεκριμένο βγαίνει (κατά τη γνώμη μου) πιο κομψό με case of:

fun foo arg m n =
  case n-m of
       1 => "expr1"
     | 2 => "expr2"
     | 3 => "expr3"
     | _ => "expr4"

Σε άλλες functional γλώσσες υπάρχουν τα guards τα οποία είναι ένας πιο κομψός τρόπος να κανεις κάτι τέτοιο. Σε Haskell πχ μπορείς να γράψεις:

foo arg m n
  | m == n-1  = "expr1"
  | m == n-2  = "expr2"
  | m == n-3  = "expr3"
  | otherwise = "expr4"
0

Πολύ καλό, δε το είχα σκεφτεί, ευχαριστώ και πάλι!

0

Να 'σαι καλά!

301 questions

289 answers

288 comments

909 users