0% found this document useful (0 votes)
7 views28 pages

PPL-PT-II Question Bank Ans Key

The document is a question bank for a Periodical Test-II covering various programming concepts. It includes questions on functions, concurrency, object-oriented programming, parameter passing methods, exception handling, and more. Additionally, it provides examples and explanations for concepts like dynamic scoping, message passing, and lambda expressions.

Uploaded by

kaishwarya978
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views28 pages

PPL-PT-II Question Bank Ans Key

The document is a question bank for a Periodical Test-II covering various programming concepts. It includes questions on functions, concurrency, object-oriented programming, parameter passing methods, exception handling, and more. Additionally, it provides examples and explanations for concepts like dynamic scoping, message passing, and lambda expressions.

Uploaded by

kaishwarya978
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 28

Periodical Test-II (Question Bank)

Part-A

1. What are the differences between a function and a procedure?

2. Write down the design issues of functions.


 Function Name: It should be descriptive and follow naming conventions for clarity.
 Parameter Passing: The method of passing parameters (by value or reference) affects how the
function interacts with variables.
 Return Value: The function may or may not return a value; the return type should be clear and
consistent.
 Side Effects: Functions should ideally avoid modifying global variables or performing I/O
operations unless necessary.
 Modularity: Functions should be small, focused, and perform a single task to promote reusability
and maintainability

3. What are the problems with concurrency?

 Non-atomic: Operations that are non-atomic but interruptible by multiple processes can cause
problems.

 Race conditions: A race condition occurs of the outcome depends on which of several
processes gets to a point first.

 Blocking: Processes can block waiting for resources. A process could be blocked for long
period of time waiting for input from a terminal. If the process is required to periodically update
some data, this would be very undesirable.

 Starvation: Starvation occurs when a process does not obtain service to progress.

 Deadlock: Deadlock occurs when two processes are blocked and hence neither can proceed to
execute

4. Differentiate process and thread?


Process Thread

Process means a program in execution. Thread means a segment of a process.

A process is an independent program in execution, A thread is a lightweight unit of a process


with its own memory space and resources. that shares the same memory space but has
its own execution context.

A process takes more time to terminate. A thread takes less time to terminate.

It takes more time for creation. It takes less time for creation.

A process does not share data with each other. Threads share data with each other.

5. Explain the following a) Event b) Semaphores

An event represents an occurrence that other parts of the system or program may listen for and
respond to. Events can trigger specific actions, such as handling user input, completing a task, or
signaling a change in state.

A semaphore is a simple mechanism that can be used to provide synchronization of tasks.


Semaphores can also be used to provide cooperation synchronization. To provide limited access to a
data structure, guards can be placed around the code that accesses the structure.

6. What is Object oriented programming? What are its key concepts?


Object-Oriented Programming (OOP) is a programming paradigm that organizes software design
around objects, which are instances of classes. It focuses on modeling real-world entities and their
interactions.

Key Concepts of OOP:

 Class: A blueprint for creating objects, defining attributes and methods.


 Object: An instance of a class that has its own data and behaviors.
 Encapsulation: Bundling data and methods inside a class and restricting access to internal details
using access modifiers.
 Abstraction: Hiding the complex implementation details and showing only the necessary
features.
 Inheritance: Allowing a new class to inherit properties and behaviors from an existing class,
promoting code reuse.
 Polymorphism: Enabling different classes to be treated as instances of the same class, allowing
for method overriding and overloading.

7. What is a simple list?


A simple list is a collection of elements or items arranged in a specific order.
In programming, a list is a data structure that holds multiple values, which can be of the same or
different types. The elements are typically stored in a sequence and can be accessed by their index
position.
Ex:
fruits = ["apple", "banana", "cherry"]

8. What is the use of the assert statement?


The assert statement is used for debugging purposes in programming. It tests a condition, and if the
condition is True, the program continues executing. If the condition is False, it raises an
AssertionError and stops the execution. It helps identify logical errors by checking if certain
conditions hold true during the program's execution.
Ex:
assert x > 0, "x must be positive"
9. What is the use of Suppress pragma in Ada?
It is used to control the suppression of specific compiler warnings or checks. It allows the
programmer to disable certain checks or warnings for a section of code where they may be deemed
unnecessary or where the programmer has ensured the safety of the code manually. This can help
avoid unnecessary compiler messages while still ensuring correct program behavior.

10. What does lambda expression specify?


A lambda expression (or lambda function) specifies an anonymous function, a function without a
name, that can be defined and used inline, often as an argument to another function.

Ex:
square = lambda x: x ** 2

11. What is Dynamic scoping


Dynamic Scoping in the context of Programming Languages (PPL) refers to a method of resolving
variable names in a program. It determines the scope of a variable based on the calling sequence of
functions, rather than the physical structure of the program

12. What are the fundamental design considerations for parameter-passing methods?
 Efficiency: The method should be efficient in terms of memory and time. For example, passing
large data by reference is faster than copying it by value.
 Functionality and Safety: The method should allow the function to behave as expected. Pass-by-
value prevents changes to the original data, while pass-by-reference allows changes to the
original data
13. Define exception handling
Exception handling allows programmers to detect and manage errors during runtime, ensuring that
the program continues executing or provides meaningful error messages rather than crashing
14. What is concurrent programming?
Concurrent programming is a programming paradigm that allows multiple tasks or processes to run
simultaneously or in an overlapping manner, improving resource utilization and performance. It is
often achieved through multithreading or parallelism

15. Explain the following terms : (a) Message passing (b) Monitors

(a) Message Passing:


Message passing is a communication method used in concurrent programming, where processes or
threads exchange data by sending and receiving messages. It is commonly used in distributed
systems or parallel processing to allow processes to interact without sharing memory directly.
(b) Monitors:
A monitor is a synchronization mechanism that ensures only one process or thread can access a shared
resource at a time. It combines both the data and the operations on the data, automatically
synchronizing access to prevent issues like race conditions and ensuring mutual exclusion

16. What is a Preprocessor directive?

A preprocessor directive is a special instruction given to the preprocessor to perform tasks before the
actual compilation of the code. These tasks typically involve including external files, defining
constants, or controlling code inclusion based on conditions.

Example:

#include: Includes header files.


#define: Defines constants or macros

17. What is a curried function?


A curried function is a function that takes multiple arguments one at a time, rather than all at once. It
transforms a function that takes multiple parameters into a series of functions, each taking a single
argument and returning another function that takes the next argument, and so on.
18. Explain the process of currying.
Currying is the process of transforming a function that takes multiple arguments into a sequence of
functions, each taking one argument. Each function returns another function that takes the next
argument, and this continues until all arguments are provided. Once all arguments are received, the
final function returns the result.

Note: **
Currying and a curried function are related concepts, but they are not exactly the same:

 Currying is the process of converting the function.


 A curried function is the output of that process.

19. What are the two forms of DEFINE?

The two forms of DEFINE are:

1. Constant Definition
2. Macro Definition

1. Constant Definition: This form is used to define a constant value using the #define directive. The
defined value can be used throughout the program. Example:

#define PI 3.14

2. Macro Definition: This form defines a macro that can take arguments and be used like a function.
It helps in reusing code.

Example:

#define SQUARE(x) ((x) * (x))


20. What does the abbreviation REPL stand for?

REPL stands for Read-Eval-Print Loop. REPL is commonly used in languages like Python,
JavaScript, and Lisp for interactive development and testing. It refers to an interactive programming
environment where:

Read: The user inputs code or commands.


Eval: The code is evaluated or executed.
Print: The result of the evaluation is printed or displayed.
Loop: The process repeats, allowing continuous interaction with the environment.

Part-B

1. Show the stack with all activation record instances, including the dynamic chain, when
execution reaches position 1 in the following skeletal program. This program uses the deep-
access method to implement dynamic scoping
void fun1() {float a; }
void fun2() { int b,c; }
void fun3() { float d; }
void main() { char e, f, g; }
The calling sequence for this program for execution to reach fun3 is
main calls fun2
fun2 calls fun1
fun1 calls fun1
fun1 calls fun3

Answer:

Understanding The Call Stack with Dynamic Scoping

The scenario describes a program execution using the deep-access method of dynamic scoping. To illustrate
the stack with all activation record instances including the dynamic chain as the execution reaches position 1
in fun3, let's follow the calling sequence:

main initializes the stack.

fun2 is called by main, creating a new activation record on top of main's.

fun1 is then called by fun2, thereby placing its activation record on top of fun2's.

Next, fun1 calls itself recursively, which adds another fun1 activation record on the stack.

Finally, fun1 calls fun3, placing fun3's activation record on top.

At position 1 in fun3, the stack from top to bottom (with the dynamic chain) would be:

 fun3 activation record (with a link back to fun1)


 fun1 activation record (with a link back to the previous fun1)
 fun1 activation record (with a link back to fun2)
 fun2 activation record (with a link back to main)
 main activation record (with no link as it is the base)

Each activation record would typically contain information such as local variables, parameters, dynamic link
to the caller, return address, and possibly other bookkeeping information.

2. Consider the following program written in C syntax complete the program with full code
void main()
{ int value = 2, list[5] = {1, 3, 5, 7, 9};
swap(value, list[0]);
swap(list[0], list[1]);
swap(value, list[value]);
} For each of the following parameter-passing methods, what are all of the values of the
variables value and list after each of the three calls to swap?
a. Passed by value
b. Passed by reference
c. Passed by value-result
Discuss the design issues of Exception Handling.

Answer:

Parameter-Passing Methods:

(a) Passed by Value

In pass-by-value, the values of value and list[0] are copied into the parameters a and b in the swap
function. Any changes made to a andb inside swap do not affect the original variables in main.

1. Initial values:
o value = 2
o list = {1, 3, 5, 7, 9}

2. First call: swap(value, list[0])


o value = 2, list[0] = 1
o a = 2, b = 1 (copies)
o After swapping: a = 1, b = 2
o The swap does not affect value or list[0] because they were passed by value.

Values after the first call:

o value = 2, list = {1, 3, 5, 7, 9}

3. Second call: swap(list[0], list[1])


o list[0] = 1, list[1] = 3
o a = 1, b = 3 (copies)
o After swapping: a = 3, b = 1
o Again, the swap does not affect the original values because they were passed by
value.

Values after the second call:

o value = 2, list = {1, 3, 5, 7, 9}

4. Third call: swap(value, list[value])


o value = 2, list[2] = 5
o a = 2, b = 5 (copies)
o After swapping: a = 5, b = 2
o No change to value or list[2] since the values are passed by value.

Values after the third call:

o value = 2, list = {1, 3, 5, 7, 9}

Final values for Pass-by-Value:

 value = 2
 list = {1, 3, 5, 7, 9}

(b) Passed by Reference

In pass-by-reference, the addresses (references) of value and the elements of list are passed to the
function. As a result, changes made to the parameters a andb inside swap directly affect the original
values of value and list.

1. Initial values:
o value = 2
o list = {1, 3, 5, 7, 9}

2. First call: swap(value, list[0])


o value = 2, list[0] = 1
o a = &value, b = &list[0] (addresses are passed)
o After swapping: value = 1, list[0] = 2

Values after the first call:

o value = 1, list = {2, 3, 5, 7, 9}

3. Second call: swap(list[0], list[1])


o list[0] = 2, list[1] = 3
o a = &list[0], b = &list[1]
o After swapping: list[0] = 3, list[1] = 2

Values after the second call:


o value = 1, list = {3, 2, 5, 7, 9}

4. Third call: swap(value, list[value])


o value = 1, list[1] = 2
o a = &value, b = &list[1]
o After swapping: value = 2, list[1] = 1

Values after the third call:

o value = 2, list = {3, 1, 5, 7, 9}

Final values for Pass-by-Reference:

 value = 2
 list = {3, 1, 5, 7, 9}

(c) Passed by Value-Result

In pass-by-value-result, the argument is passed by value initially, but the result is copied back to the
actual parameter after the function completes. This method has characteristics of both pass-by-value
(input) and pass-by-reference (output).

1. Initial values:
o value = 2
o list = {1, 3, 5, 7, 9}

2. First call: swap(value, list[0])


o value = 2, list[0] = 1
o a = 2, b = 1 (copies)
o After swapping: a = 1, b = 2
o After the function completes, the updated values a and b are copied back to value and
list[0].

Values after the first call:

o value = 1, list = {2, 3, 5, 7, 9}

3. Second call: swap(list[0], list[1])


o list[0] = 2, list[1] = 3
o a = 2, b = 3 (copies)
o After swapping: a = 3, b = 2
o After the function completes, the updated values are copied back to list[0] and list[1].

Values after the second call:

o value = 1, list = {3, 2, 5, 7, 9}


4. Third call: swap(value, list[value])
o value = 1, list[1] = 2
o a = 1, b = 2 (copies)
o After swapping: a = 2, b = 1
o After the function completes, the updated values are copied back to value and list[1].

Values after the third call:

o value = 2, list = {3, 1, 5, 7, 9}

Final values for Pass-by-Value-Result:

 value = 2
 list = {3, 1, 5, 7, 9}

3. What is an event? How the events are handled in various OOP languages.
An event is an action or occurrence that can be detected by the program, typically initiated by the user
(mouse clicks, keyboard presses etc.), or by the system (like timers or file changes).

Events are Handled in Various OOP Languages:

1. Java

In Java, events are handled using Event Listeners and Listeners. Java provides a rich set of event
classes (like ActionEvent, MouseEvent, etc.), and listeners (like ActionListener, MouseListener) that
handle these events.

Example:

import java.awt.event.*;
import javax.swing.*;

public class ButtonExample {


public static void main(String[] args) {
JFrame frame = new JFrame();
JButton button = new JButton("Click me");

// Event handling using ActionListener


button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
});

frame.add(button);
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
In this example, the ActionListener handles the click event on the button.

2. C#

In C#, events are handled using delegates. An event is declared using the event keyword and is
usually triggered by a specific action.

Example:

using System;

class Program {
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler MyEvent;

public void TriggerEvent() {


MyEvent?.Invoke(this, EventArgs.Empty); // Triggers the event
}

static void Main(string[] args) {


Program program = new Program();
program.MyEvent += (sender, e) => { Console.WriteLine("Event Triggered!"); };

program.TriggerEvent(); // Trigger the event


}
}

Here, an event MyEvent is triggered by invoking the TriggerEvent method, and a handler is added
using the += operator.

3. JavaScript

JavaScript handles events in a browser environment using Event Listeners. DOM elements can listen
for events (like click, keydown, etc.) and execute specified callback functions.

Example:

javascript
Copy
const button = document.getElementById('myButton');

button.addEventListener('click', function() {
alert('Button clicked!');
});

In this example, the event listener listens for the click event on the button and shows an alert when it
occurs.

4. Python (with Tkinter or Pygame)

Python handles events using libraries such as Tkinter (for GUIs) or Pygame (for games). In Tkinter,
events are handled by binding event handlers to specific widgets.
Example with Tkinter:

import tkinter as tk

def on_button_click():
print("Button clicked!")

root = tk.Tk()
button = tk.Button(root, text="Click me", command=on_button_click)
button.pack()
root.mainloop()

4. Describe the deep-access method of implementing dynamic scoping.


In dynamic scoping, a variable's value is determined by searching the call stack (the chain of function
calls) at runtime, rather than by looking up variable bindings in the lexical environment (as in static
scoping). The deep-access method is one way to implement dynamic scoping in a programming
language.

Deep-Access Method:

The deep-access method refers to how dynamic scoping is implemented by searching for variable
bindings within the call stack. This method is so-called because it involves "deeply" searching
through the active function calls at runtime, starting from the current function and moving outward
through its caller functions.

Steps in Deep-Access Method:

1. Initial Variable Lookup: When a variable is accessed inside a function, the runtime
environment first checks if the variable is locally defined within that function.
2. Search Through Call Stack: If the variable is not found locally, the system then searches the
caller's environment, and if it is still not found, the search continues further up the call stack
through each function call that led to the current execution point.
3. Dynamic Binding: This search is performed dynamically at runtime, meaning that the value
of a variable can change depending on the context of the function calls at that particular
moment.
4. Global Scope: If the variable is not found within the call stack, it is checked in the global
environment (the environment outside all functions). If the variable is not found there, an error
is typically raised.

var x = 10; // global binding

function A() {

var x = 20; // local binding in A

B(); // call to B

function B() {

print(x); // will print 20 in dynamic scoping


}

A(); // Calling function A

Advantages of Deep-Access Method in Dynamic Scoping:

 Flexibility
 Easy of Use

Disadvantages of Deep-Access Method in Dynamic Scoping:

 Difficulty in Debugging
 Unintended Variable Shadowing
 Performance Overhead

5. Explain Methods of Providing Synchronization in detail with an example

Synchronization in programming refers to the coordination of multiple threads or processes to ensure that they
execute in a safe and predictable manner, especially when they share resources like memory, files, or
hardware. Without proper synchronization, concurrent threads or processes may access shared resources at the
same time, causing conflicts, data corruption, or unpredictable behavior.

1. Locks (Mutexes)

A lock (also called a mutex) is the simplest and most common method for ensuring that only one thread can
access a shared resource at a time. When a thread locks a resource, other threads are blocked from accessing it
until the lock is released.

 Mutex (Mutual Exclusion): A mutex is an object used to manage access to a resource. A thread must
acquire the mutex before accessing the shared resource, and release it when done.

Example in Python (using threading):


import threading

# Shared resource
counter = 0

# Mutex (lock) to synchronize access to the shared resource


lock = threading.Lock()

def increment():
global counter
with lock: # Lock the resource before accessing
counter += 1
print(f"Counter value: {counter}")

# Create threads
threads = []
for _ in range(5):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join() # Wait for all threads to complete

2. Semaphores

A semaphore is a synchronization primitive that controls access to a shared resource by maintaining a set of
permits. It allows a specified number of threads to access a resource simultaneously. If no permits are
available, threads must wait until a permit is released.

 Binary Semaphore (also called a Mutex): This is a semaphore with only two states (0 or 1). It can be
used for mutual exclusion, similar to a lock.
 Counting Semaphore: It allows a fixed number of threads to access a shared resource concurrently.

Example in Python (using threading):


import threading
import time

# Semaphore with 2 permits


semaphore = threading.Semaphore(2)

def access_resource(thread_id):
print(f"Thread-{thread_id} is waiting for the semaphore")
semaphore.acquire() # Wait for a permit
print(f"Thread-{thread_id} is accessing the resource")
time.sleep(2) # Simulate some work
print(f"Thread-{thread_id} is releasing the semaphore")
semaphore.release() # Release the permit

# Create threads
threads = []
for i in range(5):
t = threading.Thread(target=access_resource, args=(i,))
threads.append(t)
t.start()

for t in threads:
t.join() # Wait for all threads to complete

3. Condition Variables

A condition variable allows threads to wait for certain conditions to be true before proceeding with
execution. Condition variables are often used in conjunction with a lock or mutex to protect access to shared
resources.

Threads can wait for a condition to be met, and another thread can signal when the condition is met (usually
through notify() or notify_all()).

Example in Python (using threading):


import threading
import time

# Shared resource and a condition variable


condition = threading.Condition()
counter = 0
def increment():
global counter
with condition:
counter += 1
print(f"Counter incremented to: {counter}")
condition.notify() # Notify waiting threads

def wait_for_increment():
with condition:
condition.wait() # Wait for notification
print("Condition met, proceeding with work")

# Create threads
threads = []
for _ in range(3):
t = threading.Thread(target=wait_for_increment)
threads.append(t)
t.start()

# Let some time pass before incrementing


time.sleep(2)

# Increment the counter and notify all waiting threads


increment_thread = threading.Thread(target=increment)
increment_thread.start()

for t in threads:
t.join()

increment_thread.join()

4. Read-Write Locks

A read-write lock allows multiple threads to read from a shared resource simultaneously, but gives exclusive
access to one thread for writing. This improves performance when there are frequent read operations and few
write operations.

 Read Lock: Multiple threads can acquire the read lock and read the resource simultaneously.
 Write Lock: Only one thread can acquire the write lock, and it has exclusive access to the resource.

Example in Python (using threading):


import threading

# Shared resource
data = 0

# Read-Write lock class


class ReadWriteLock:
def __init__(self):
self.read_lock = threading.Lock()
self.write_lock = threading.Lock()
self.readers = 0
def acquire_read(self):
with self.read_lock:
self.readers += 1
if self.readers == 1:
self.write_lock.acquire() # First reader blocks writers

def release_read(self):
with self.read_lock:
self.readers -= 1
if self.readers == 0:
self.write_lock.release() # Last reader releases the writer lock

def acquire_write(self):
self.write_lock.acquire()

def release_write(self):
self.write_lock.release()

# Initialize the ReadWriteLock


rw_lock = ReadWriteLock()

# Example of reading and writing with the ReadWriteLock


def read_data():
rw_lock.acquire_read()
print(f"Reading data: {data}")
rw_lock.release_read()

def write_data(value):
rw_lock.acquire_write()
global data
data = value
print(f"Writing data: {data}")
rw_lock.release_write()

# Threads to simulate read and write operations


threads = []
for _ in range(3):
t = threading.Thread(target=read_data)
threads.append(t)
t.start()

write_thread = threading.Thread(target=write_data, args=(42,))


threads.append(write_thread)
write_thread.start()

for t in threads:
t.join()

5. Barriers

A barrier is a synchronization mechanism used to block threads until all threads reach a certain point in the
program, ensuring they proceed together. This is commonly used in parallel computing when multiple threads
need to synchronize at specific points.
Example in Python (using threading):

# Barrier to synchronize 3 threads


barrier = threading.Barrier(3)

def task(thread_id):
print(f"Thread-{thread_id} starting")
barrier.wait() # Wait for other threads to reach the barrier
print(f"Thread-{thread_id} proceeding after the barrier")

# Create threads
threads = []
for i in range(3):
t = threading.Thread(target=task, args=(i,))
threads.append(t)
t.start()

for t in threads:
t.join()

6. Write the procedure to compute the factorial function by using ML

ML (Meta Language) family of programming languages, can compute the factorial function using recursion
or an iterative approach. The recursive approach is the most natural way to express the factorial function, as
it directly reflects the mathematical definition of factorial.

Recursive Implementation of Factorial in ML

A Recursive function can be defined as a routine that calls itself directly or indirectly. It is
particularly useful for problems that can be broken down into smaller subproblems, such as computing
the factorial of a number.

Need of Recursive Function:


A recursive function is a function that solves a problem by solving smaller instances of the same problem.
This technique is often used in programming to solve problems that can be broken down into simpler,
similar subproblems.
1. Solving complex tasks:
Recursive functions break complex problems into smaller instances of the same problem, resulting in
compact and readable code.
2. Divide and Conquer:
Recursive functions are suitable for divide-and-conquer algorithms such as merge sort and quicksort,
breaking problems into smaller subproblems, solving them recursively, and merging the solutions with the
original problem.
3. Backtracking:
Recursive backtracking is ideal for exploring and solving problems like N-Queens and Sudoku.
4. Dynamic programming:
Recursive functions efficiently solve dynamic programming problems by solving subproblems and
combining their solutions into a complete solution.
5. Tree and graph structures:
Recursive functions are great for working with tree and graph structures, simplifying traversal and pattern
recognition tasks.
Example:

# Recursive Function to calculate Factorial of a number

def factorial(n):
# Base case
if n == 0:
return 1

# Recursive case
return n * factorial(n - 1)

# Driver Code
if __name__ == "__main__":
n=4
print("Factorial of", n, "is:", factorial(n))

Output:

Factorial of 4 is:24
7. Write a prolog description of your family tree (based only on facts), going back to your
grandparents and including all descendants. Be sure to include all relationships.

In Prolog, we define family relationships using facts and rules.

 Facts: These are statements about specific individuals (like "John is Mary's parent").
 Rules: These are logical statements that help derive new facts (like "John is Mary's grandparent if
John is the parent of Mary's parent").

Example :
% Facts about parents
parent(john, mary). % John is the parent of Mary
parent(john, james). % John is the parent of James
parent(jane, mary). % Jane is the parent of Mary
parent(jane, james). % Jane is the parent of James

parent(mary, lisa). % Mary is the parent of Lisa


parent(mary, tom). % Mary is the parent of Tom
parent(steve, lisa). % Steve is the parent of Lisa
parent(steve, tom). % Steve is the parent of Tom

parent(james, anna). % James is the parent of Anna


parent(kate, anna). % Kate is the parent of Anna

parent(tom, sophie). % Tom is the parent of Sophie


parent(susan, sophie). % Susan is the parent of Sophie

% Facts about grandparent relationships


grandparent(X, Y) :-
parent(X, Z),
parent(Z, Y).

% Facts about siblings


sibling(X, Y) :-
parent(Z, X),
parent(Z, Y),
X \= Y. % Ensure they are different individuals

% Facts about aunts and uncles


aunt_or_uncle(X, Y) :-
sibling(X, Z),
parent(Z, Y).

% Facts about niece and nephew


niece_or_nephew(X, Y) :-
aunt_or_uncle(Y, X),
female(X). % Assuming X is a female to be a niece

niece_or_nephew(X, Y) :-
aunt_or_uncle(Y, X),
male(X). % Assuming X is a male to be a nephew

% Facts about gender


female(mary).
female(jane).
female(lisa).
female(anna).
female(sophie).
male(john).
male(james).
male(steve).
male(tom).
male(susan).
male(kate).
Explanation of Facts:

1. parent(X, Y): This fact states that X is the parent of Y.


o For example, parent(john, mary) means John is the parent of Mary.
2. grandparent(X, Y): This rule defines a grandparent relationship. X is a grandparent of Y if X is a
parent of someone (Z), and Z is a parent of Y.
o For example, grandparent(john, lisa) means that John is a grandparent of Lisa, since John is
the parent of Mary, and Mary is the parent of Lisa.
3. sibling(X, Y): This rule defines sibling relationships. X and Y are siblings if they share at least one
common parent and are not the same individual.
o For example, sibling(mary, james) means Mary and James are siblings.
4. aunt_or_uncle(X, Y): This rule defines the relationship of an aunt or uncle. X is an aunt or uncle of Y
if X is a sibling of Y's parent.
o For example, aunt_or_uncle(mary, sophie) means Mary is an aunt to Sophie, since Mary is a
sister of Tom, and Tom is Sophie’s parent.
5. niece_or_nephew(X, Y): This rule defines the relationship of niece or nephew. X is a niece or
nephew of Y if Y is an aunt or uncle of X, and X is either male or female (using gender facts).
o For example, niece_or_nephew(sophie, mary) means Sophie is the niece of Mary.
6. Gender facts: The female(X) and male(X) facts specify the gender of each individual. For example,
female(mary) means Mary is female, and male(john) means John is male.

8. Consider the following C++ skeletal program:


class Big { int i;
float f;
void fun1() throw int {
try {
throw i;
throw f; }
catch(float) { . . . } }}
class Small {
int j;
float g;
void fun2() throw float { try {
try {
Big.fun1();
. . . throw j;
. . . throw g;

catch(int) { . . . }
}
catch(float) { . . . }

} In each of the four throw statements, where is the exception handled? Note that fun1 is called from
fun2 in class Small.

In this C++ skeletal program, there are multiple throw statements inside two classes: Big and Small. We need
to understand where each exception is caught based on the throw statements inside both classes.
Class Big and fun1() Method:

class Big {
int i;
float f;

void fun1() throw(int) {


try {
throw i; // 1st throw statement (throws int)
throw f; // 2nd throw statement (throws float)
}
catch(float) {
// Handle float exception
}
}
};

In the Big class, the fun1() method throws two types of exceptions:

1. throw i;: This throws an exception of type int (since i is of type int).
2. throw f;: This throws an exception of type float (since f is of type float).

Where are these exceptions handled?

 The first exception (throw i;) is thrown inside fun1() and is an int. The program will look for a
catch(int) block, but there is none explicitly present. However, if this exception is thrown, it will not
be caught by the catch(float) block, because it is only designed to handle float exceptions. In this case,
the program doesn't show the catch(int) block, so this exception may cause the program to
terminate unless explicitly handled elsewhere (not shown in the code).
 The second exception (throw f;) is a float exception and is caught by the catch(float) block inside
the fun1() method. This is where the float exception is handled.

Class Small and fun2() Method:

cpp
Copy
class Small {
int j;
float g;

void fun2() throw(float) {


try {
try {
Big.fun1(); // Calls fun1() of class Big
. . . throw j; // 3rd throw (throws int)
. . . throw g; // 4th throw (throws float)
}
catch(int) {
// Handle int exception in fun2
}
}
catch(float) {
// Handle float exception in fun2
}
}
};

In the Small class, the method fun2() calls fun1() from Big. There are two throw statements in fun2():

1. throw j;: Throws an exception of type int (since j is of type int).


2. throw g;: Throws an exception of type float (since g is of type float).

Where are these exceptions handled?

 Inside fun2(), there is a try-catch block that surrounds the call to Big::fun1(). After that, there are two
throw statements.

Handling the Exceptions:

1. First Exception: throw i; in Big::fun1():


o When fun1() throws the int exception (throw i;), the exception is not caught inside fun1()
because there is no catch(int) block in fun1().
o Since fun1() is called inside fun2(), the int exception is propagated up to fun2() in class
Small.
o Inside fun2(), there is a catch(int) block. So, the int exception is caught by this block and
handled accordingly.

2. Second Exception: throw f; in Big::fun1():


o The float exception (throw f;) is thrown inside fun1() of Big and is caught by the catch(float)
block inside fun1().
o Since fun1() itself handles this exception, it is not propagated back to fun2().

3. Third Exception: throw j; in fun2() of Small:


o The int exception (throw j;) is thrown inside fun2(). It is handled by the catch(int) block
inside fun2().

4. Fourth Exception: throw g; in fun2() of Small:


o The float exception (throw g;) is thrown inside fun2(). It is handled by the catch(float) block
in fun2().

9. Write a program that asks the user for a number and displays ten times the number. Also the program
must throw an exception when the user enters a value greater than 10
10. Explain about Parameter Passing methods with detailed example.

11. Define monitor. Explain how cooperation synchronization and competition synchronization are
implemented using monitors.
12. Explain about the types of Dynamic Scoping.

There are primarily two types of dynamic scoping:

1. Deep Access (Deep Dynamic Scoping)

In deep access dynamic scoping, the variable lookup starts from the current function's activation
record, and if the variable isn't found, the search continues back through the stack (activation records
of previous function calls) to find the variable. The lookup will follow the entire call chain.
How it works:

 If a function accesses a variable, the search for that variable starts from its own activation
record.
 If the variable is not found in the current function, it checks the activation record of the
function that called it.
 This continues until the search reaches the top of the call stack (the main function or the
program's entry point).

Advantages:

 It allows functions to have access to variables from any function in the call stack, providing
flexibility.

Disadvantages:

 Deep dynamic scoping can make it difficult to reason about variable bindings and values,
since variables from any function in the call chain can be accessed at any point.
 It can also make the program harder to maintain and debug, as it increases the chances of
variable name conflicts or unintended side effects.

2. Shallow Access (Shallow Dynamic Scoping)

In shallow access dynamic scoping, when a variable is referenced, it is first looked up in the current
function’s activation record. However, if the variable is not found in the current function, it only looks
in the immediate caller's activation record, not continuing up the stack beyond that.

How it works:

 If a function accesses a variable, the search first looks in its own activation record.
 If the variable is not found, the search moves one level up the call stack (the calling function's
activation record), but does not go beyond that. The search stops there.

Advantages:

 It is easier to understand and debug than deep dynamic scoping, because it is clear that only
the immediate caller's scope is relevant.
 The scope of variable lookup is restricted, which can prevent unintended variable shadowing
or conflicts.

Disadvantages:

 It is less flexible than deep dynamic scoping, because it only allows access to the most
immediate caller's scope.
 This can limit the ability of functions to access variables in more distant function calls in the
call chain.

13. Write short notes on implementing subprograms.


A subprogram can be defined in several forms, such as:

 Functions: Return a value after execution.


 Procedures: Do not return a value but may alter data.
 Methods: Associated with objects in object-oriented programming.

Types of Subprograms

Subprograms are broadly classified into:

 Functions: A function takes input, performs operations, and returns a value. It may
take parameters and has a return type.
o Example: In C++, a function to calculate the factorial of a number:

int factorial(int n) {
if (n == 0) return 1;
else return n * factorial(n - 1);
}

 Procedures: Procedures perform an action but do not return a value. They may
modify the state or execute side effects.
o Example: In Pascal, a procedure to print a message:

procedure PrintMessage(message: string);


begin
writeln(message);
end;

 Methods: Methods are subprograms that are part of a class in object-oriented


programming (OOP). Methods typically operate on the data of the class (its
attributes).
o Example: In Java, a method inside a class:

class Calculator {
public int add(int a, int b) {
return a + b;
}
}

3. Parameters and Arguments

Subprograms often accept input parameters (arguments) to operate on. Parameters are defined
in the subprogram's header, while arguments are passed when the subprogram is called.

 Formal Parameters: Parameters defined in the subprogram signature.


 Actual Parameters: Values passed during the call of the subprogram.

There are two common ways to pass arguments:

 Call-by-Value: The actual value of the argument is passed, meaning changes to the
parameter do not affect the argument.
 Call-by-Reference: A reference to the actual argument is passed, meaning any change
in the parameter will affect the argument.

4. Local and Global Variables

 Local Variables: Variables declared inside a subprogram. They are created when the
subprogram is invoked and destroyed when the subprogram exits.
 Global Variables: Variables declared outside any subprogram and can be accessed by
any part of the program. However, relying on global variables in subprograms may
lead to errors due to shared access.

5. Return Values

 Functions typically return a value using the return keyword.


 Procedures generally do not return any value but may affect global or passed
parameters.
 A return value may have any data type, depending on the subprogram’s declaration.

6. Recursive Subprograms

A recursive subprogram is a subprogram that calls itself to solve smaller instances of a


problem. Recursion is a powerful technique, but it must have a base case to avoid infinite
loops. Example (Factorial Function in C++):

int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}

7. Error Handling in Subprograms

 Exception Handling: In some programming languages (like Python, Java),


subprograms can handle exceptions to manage errors gracefully.
 Return Codes: In C/C++, subprograms often return error codes to indicate failure or
success.

Example in Python:

def divide(a, b):


try:
return a / b
except ZeroDivisionError:
return "Error: Division by zero"

8. Subprograms in Object-Oriented Programming (OOP)

In OOP languages (like Java, C++, Python), subprograms are often encapsulated within
classes as methods. Methods operate on the data (attributes) of the object and can modify its
state.
 Methods can have access modifiers (public, private) to control visibility and
encapsulation.
 Constructors are special subprograms used for initializing objects.

Example of a constructor in Java:

class Car {
String model;

public Car(String model) {


this.model = model;
}
}

9. Subprogram Overloading

Languages like C++, Java, and Python, subprograms can be overloaded. This means you can
define multiple subprograms with the same name but different parameters.

14. Explain about LISP functional programming language


LISP (LISt Processing) is one of the oldest programming languages, designed by John McCarthy in
1958 at MIT. It is a functional programming language primarily used for symbolic computation,
artificial intelligence (AI), and rapid prototyping. LISP has significantly influenced the development
of many programming languages, especially those in the functional paradigm

Features of LISP:

 Functional Programming Paradigm : LISP is based on functional programming, where


functions are first-class citizens and computation is treated as the evaluation of functions.
 S-Expressions (Symbolic Expressions): The syntax is based on S-expressions, which are
parenthesized lists that represent both code and data in LISP.
 Recursion: LISP relies heavily on recursion instead of loops for repetitive tasks, making it
ideal for mathematical and symbolic computations.
 First-Class Functions: Functions can be passed as arguments, returned from other functions,
and assigned to variables.
 Higher-Order Functions: LISP supports higher-order functions, meaning functions can take
other functions as arguments or return functions as results.
 Macros: LISP allows the definition of macros, enabling the creation of new control structures
or syntactic constructs.
 Automatic Garbage Collection: LISP automatically manages memory by reclaiming
memory occupied by unused objects, preventing memory leaks.
 REPL (Read-Eval-Print Loop): LISP provides an interactive programming environment
where developers can test and evaluate expressions in real-time.
 Dynamic Typing: LISP is dynamically typed, meaning variable types are determined at
runtime, not at compile time.
 Lists as Core Data Structure: LISP’s fundamental data structure is the list, and it treats code
and data similarly as lists.
 Portable and Extensible: Various dialects of LISP, such as Common Lisp, Scheme, and
Clojure, offer portability and extensibility to modern development environments.
 AI and Symbolic Computation: LISP has been traditionally used in artificial intelligence
(AI), symbolic computation, and natural language processing due to its ability to handle
complex data structures.

15. Explain list structures and Goal statements in PROLOG.

PROLOG (Programming in Logic) is a logic programming language used primarily for


artificial intelligence (AI) and computational linguistics. It is based on formal logic, where the
primary way to express relationships and solve problems is through facts and rules.
PROLOG uses list structures to represent and manipulate data, and goal statements to query
or search for solutions.

1. List Structures in PROLOG

In PROLOG, a list is a fundamental data structure used to store collections of items. Lists are an
ordered sequence of elements enclosed in square brackets ([]). Each list can hold any type of data,
including atoms, numbers, or other lists.

Basic List Structure:

 A list can be empty: [].


 A list can have elements: [Head | Tail].
o Head is the first element of the list.
o Tail is the rest of the list (can be another list or empty).

Example:

[1, 2, 3, 4].

Here, the list contains four elements: 1, 2, 3, and 4.

Head and Tail:

In PROLOG, you can access the head (first element) and tail (remaining elements) of a list using
pattern matching.

Example:

[Head | Tail] = [1, 2, 3, 4].

Head = 1,
Tail = [2, 3, 4].

The Head is 1, and the Tail is [2, 3, 4].

List Operations:

PROLOG has several built-in predicates for manipulating lists, such as:
 member(X, List): Checks if element X is a member of the list.
 append(List1, List2, Result): Appends two lists.
 length(List, Length): Finds the length of a list.

Example of member/2:

member(2, [1, 2, 3, 4]).


true.

PROLOG lists are widely used to represent things like:

 Knowledge representations: Facts, relationships, or attributes can be represented as lists.


 Search solutions: Lists can be used to store possible solutions in recursive algorithms.

2. Goal Statements in PROLOG

In PROLOG, a goal statement is essentially a query that asks the system to find values that satisfy
certain conditions defined by facts and rules. A goal is a query that PROLOG tries to satisfy using
backtracking—systematically exploring possible solutions.

Goal statements are written as predicates (logical assertions or relationships) followed by arguments.
These predicates can be:

 Facts: Basic assertions.


 Rules: Logical relationships based on facts.

Structure of Goal Statements:

A goal can be a simple fact or a complex query involving multiple conditions and logic.

Example of a fact:

father(john, mary).

This fact asserts that John is the father of Mary.

Example of a goal:

father(john, X).

This goal asks, "Who is the child of John?" The system will return X = mary based on the fact
father(john, mary).

Example of a Rule:

A rule defines relationships between facts. It is written as:

ancestor(X, Y) :- father(X, Y).

This rule states that X is an ancestor of Y if X is the father of Y. The :- symbol is read as "if" or "is
true if."
Backtracking in PROLOG:

PROLOG uses backtracking to find solutions to goals. If the first attempt to satisfy a goal fails,
PROLOG tries other possible options (facts and rules) systematically until it either finds a solution or
exhausts all possibilities.

Example with backtracking:

father(john, mary).
father(john, paul).

father(john, X).

This goal will first match father(john, mary) and return X = mary. Then, backtracking occurs, and
PROLOG will match father(john, paul) and return X = paul.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy