I have the following question:
Define the functions
and, or :: [Bool] -> Bool
which give the conjunction and disjunction of a list of Booleans. For instance,
and [False, True] = False or [False, True] = True
On an empty list
and
givesTrue
andor
givesFalse
; explain the reason for these choices.
I know I can answer it but am not sure of the most efficient way to lay it out. Any help would be much appreciated.
My solution was this (but I think it could be more efficient):
and, or :: [Bool] -> Bool
and [] = True
and [True, True] = True
and [False, False] = True
and [True, False] = False
or [] = False
or [True, True] = False
or [False, False] = False
or [True, False] = True
The key step you're going to have to make is to think inductively . Your current solution:
and :: [Bool] -> Bool
and [] = True
and [True, True] = True
and [False, False] = True
and [True, False] = False
enumerates some of the possibilities, but it obviously doesn't work for all lists. So how to write one that will work for lists of any length?
In Haskell, you can usually write your functions by taking apart a data type. In this case, lists. Lists are defined as:
data [a] = []
| a : [a]
So, lists have two cases: either the empty list, or a one element with a tail. Let's start writing your and
function then, so that it matches those two cases for lists:
and [] = True
and (a:as) = ...
So, the "base case", the empty list, is True
. But what should we do for the case of a list with one element, and some tail?
Well, we already have the &&
function in Haskell:
> True && True
True
> True && False
False
> False && True
False
> False && False
False
Interesting! So, &&
takes two arguments, and correctly determines if both arguments are True. And we are currently have a list with one element, and a list for a tail. And at the same time, we're defining the and
function, that results in a single boolean value when applied to a list.
So we can make the inductive step and use the function we're defining, and
, together with the &&
binary operator, to finish our definition:
and [] = True
and (a:as) = a && (and as)
So we evaluate the tail of the list to some value (recursively), and use the &&
operator to combined that value with the current value, and that's our function written.
Recursion and induction, driven by the recursive structure of the lists, are the key technique to learn in programming. If you can write this, you're making a big step forward.
I would suggest to use pattern matching to dissect the list. Start with these condidtions:
and [] = True
and (True : xs) = ...
and (False : xs) = ...
OK, for an empty list and
is True
. If a list starts with a " True
" head, how do you determinde the "truth" of the complete list? Do you need a recursive call or not? What if you have a " False
" head?
The or
case is similar, just start with or [] = False
Note that when you start with these definitions, which already pattern match on the truth values, you don't even need to use &&
or ||
.
Here are few bits from me:
and [] = True
and (True : xs) = and xs
and (False : xs) = False
or [] = False
or (True : xs) = True
or (False : xs) = or xs
Sorry, if I have spoiled the "homework" mode of this question.
i tried to solve this with folds
and = foldl (&&) True
or = foldl (||) False
this would be a simple solution to write - but i think a more abstract one and takes a [Bool] and &&s the first element of this list with the accumulator True this result will be the next accumulator to foldl
with.
yours ε/2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.