Haskell: Nested List Comprehension - haskell

I have an assignment for school, that I need help on. So far I've created two types, Argument and Predicate, per the assignment instructions.
In this project, I have to create a list, titled 'context', of arguments (or, objects) in the world AND a list of facts about these objects, in a list titled 'facts'.
So, for instance, the context list has arguments "john" and "boston" and then in our fact list we can create a predicate with the function fly to have a fact "fly john to_boston" where to denotes that John flies to Boston.
For the final step of the project, we have to be able to ask Haskell: "qWhere fly john" and have Haskell search the context list for "john" and use that to search the list of facts for "fly" and "john" in order to eventually return "to_boston" or "boston."
I understand that this is nested list comprehension, but I don't understand how to get Haskell to return "to_boston" once it has "fly john". I'll include bits of the code below (scroll to the bottom for what I've been working on):
{-# LANGUAGE MultiParamTypeClasses #-}
-- GL TYPES
data Type = HUMN | -- human
ANIM | -- animate
ORGN | -- organic
ORGZ | -- organization
PHYS | -- physical object
ARTF | -- artifact
EVNT | -- event
PROP | -- proposition
INFO | -- information
SENS | -- sensation
LOCA | -- location
TIME | -- time period
ATTD | -- attitude
EMOT | -- emotion
PPTY | -- property
OBLG | -- obligation
RULE -- rule
deriving (Show, Eq, Enum)
-- CUSTOM DATA TYPES
data Argument = Argument { ttype :: Type, value :: String }
deriving (Show, Eq)
data Predicate = Predicate { lemma :: String
, arguments :: [Argument] }
deriving (Show, Eq)
type Context = [Argument]
-- CREATE SEMANTICALLY TYPED ARGUMENTS AS FOLLOWS
date :: String -> Argument
date s = Argument { ttype = TIME, value = s }
time :: String -> Argument
time s = Argument { ttype = TIME, value = s }
location :: String -> Argument
location s = Argument { ttype = LOCA, value = s }
human :: String -> Argument
human s = Argument { ttype = HUMN, value = s }
phys :: String -> Argument
phys s = Argument { ttype = PHYS, value = s }
artifact :: String -> Argument
artifact s = Argument { ttype = ARTF, value = s }
animate :: String -> Argument
animate s = Argument { ttype = ANIM, value = s }
-- CREATE ENTITIES/PPs AS FOLLOWS
may15 = date "May 15, 2014"
sevenAM = time "7:00"
sandiego = location "San Diego"
john = human "John"
mary = human "Mary"
boston = location "Boston"
ball = phys "ball"
car = artifact "car"
cat = animate "cat"
mouse = animate "mouse"
to_boston = to boston
context = [
may15,
sevenAM,
sandiego,
john,
mary,
boston,
ball,
cat,
mouse
]
-- HELPER FUNCTIONS
getValue :: Argument -> String
getValue c = value c
getType :: Argument -> Type
getType c = ttype c
isType :: Argument -> Type -> Bool
isType c t = (ttype c == t)
-- CREATE PREPOSITIONS AS FOLLOWS
to :: Argument -> Predicate
to x = Predicate { lemma = "to", arguments = [x] }
-- CREATE VERBS AS FOLLOWS
class Fly a b where
fly :: a -> b -> Predicate
instance Fly Argument Argument where
fly x y = Predicate { lemma = "fly", arguments = [x, y] }
--overwrite lemma,
instance Fly Argument Predicate where
fly x y = Predicate { lemma = lemma y
, arguments = [x, arguments y !! 0] }
facts = [fly john to_boston, fly mary to_boston]
-- THIS IS WHERE I'M STUCK\/
qWhere :: (Argument -> Argument -> Predicate) -> Argument
-> [[Argument]]
qWhere f x = [[arguments z | ]| z <- facts, x `elem` (arguments z)]
-- THIS RETURNS THE ENTIRE STATEMENT:
qWhere f x = [[arguments z | ]| z <- facts, x `elem` (arguments z)]

I don't think you need/want nested list comprehension. First you need to understand that list comprehension is really just syntactic sugar.
But we can use let ... in syntax to make use of multiple list comprehensions. A solution could look like this:
qWhere :: (Argument -> Argument -> Predicate)
-> Argument
-> [[Argument]]
qWhere f x = case find (== x) context of
Just e ->
-- first we get all facts about e.g. john
let personFacts = [z | z <- facts, e `elem` arguments z]
-- then we get all facts when we apply f to john and
-- any other arguments that exist in john
actionFacts = fmap (f e) (concatMap arguments personFacts)
-- and extract all arguments of those facts
actionArgs = concatMap arguments actionFacts
-- and can finally build the actual list of facts,
-- reduced by checking if the argument "john" is in one of our
-- actionArgs where we applied f to
in map arguments [z | z <- personFacts, e `elem` actionArgs]
Nothing -> []
You might need to import Data.List.

Related

Modifying a list using recursion

I have a list with elements of type LocalType (defined below), I wish to modify this list in function of which subtptype the element is belonging too.
An element of type End stays in the list of type End. For an element of type Prl (End Bar End), the first End shall stay in the list, the second End shall be appended to the list.
E.g [End, (Prl s Bar ss)] -> [End, s, ss]
E.g [End, End Bar End] -> [End, End, End]
This is how I thought of implementing it,
sepTimes :: [LocalType] -> [LocalType]
sepTimes(x:[]) = [x]
sepTimes(x:xs)
| x == End = sepTimes (x:xs)
| x == (Prl s Bar ss) = do
sepTimes (s:xs)
sepTimes (ss:xs)
As the error messages states, I am unable to retrive the elements s and ss corresponding to End and End in the example of Prl (End Bar End).
app\Sequents.hs:44:17: error: Variable not in scope: s :: LocalType
|
44 | | x == (Prl s Bar ss) = do
| ^
app\Sequents.hs:44:23: error:
* Variable not in scope: ss :: LocalType
* Perhaps you meant `xs' (line 42)
|
44 | | x == (Prl s Bar ss) = do
| ^^
app\Sequents.hs:45:19: error: Variable not in scope: s :: LocalType
|
45 | sepTimes (s:xs)
| ^
app\Sequents.hs:46:19: error:
* Variable not in scope: ss :: LocalType
* Perhaps you meant `xs' (line 42)
|
46 | sepTimes (ss:xs)
| ^^
Here are the defined datatypes :
data Seperator = Bar | BackAmpersand
deriving (Show, Eq, Ord, Read)
data LocalType = End
| Prl LocalType Seperator LocalType
deriving (Eq, Ord, Read)
You're confusing equality checks with pattern matching. Intuitively, all of the following should be the same:
f :: Either Int Char -> String
f (Left i) = show i
f (Right c) = [c]
f :: Either Int Char -> String
f x = case x of
Left i -> show i
Right c -> [c]
f :: Either Int Char -> String
f x
| x==Left i = show i -- what?
| x==Right c = [c]
But actually, only the first two are equivalent, the last one doesn't work. Why? You can't match a variable out of an equality statement. That may work in some logical languages where the equality is propositional, but Haskell's == operator is simply boolean: it takes two fully known values and tells you whether or not they're exactly the same. I.e., in order to be able to write x==Left i, the variable i must already be defined.

Simulating non-deterministic choice through the List Monad

I'm trying to write an evaluation function for a language that I am working on in which non-determinism can be permitted within an if-block, called a selection block. What I'm trying to achieve is the ability to pick an if/selection statement from the block whose guard is true and evaluate it but it doesn't matter which one I pick.
From searching, I found an example that performs in a similar way to what I would like to achieve through modelling coinflips. Below is my adapation of it but I'm having issue in applying this logic to my problem.
import Control.Monad
data BranchType = Valid | Invalid deriving (Show)
data Branch = If (Bool, Integer) deriving (Show, Eq)
f Valid = [If (True, 1)]
f Invalid = [If (False, 0)]
pick = [Invalid, Invalid, Valid, Invalid, Valid]
experiment = do
b <- pick
r <- f b
guard $ fstB r
return r
s = take 1 experiment
fstB :: Branch -> Bool
fstB (If (cond, int)) = cond
main :: IO ()
main = putStrLn $ show $ s -- shows first branch which could be taken.
Below is my ADT and what I have been trying to make work:
data HStatement
= Eval HVal
| Print HVal
| Skip String
| Do HVal [HStatement]
| If (HVal, [HStatement])
| IfBlock [HStatement] -- made up of many If
| Select [HStatement] -- made up of many If
deriving (Eq, Read)
fstIf :: HStatement -> Bool
fstIf (If (cond, body)) = if hval2bool cond == True
then True
else False
h :: Env -> HStatement -> IOThrowsError ()
h env sb = do
x <- g env sb
guard $ fstIf x -- Couldn't match expected type ‘HStatement’ with actual type ‘[HStatement]’
-- after guard, take 1 x then evaluate
g :: Env -> HStatement -> IOThrowsError [HStatement]
g env (Select sb) = mapM (\x -> f env x) sb
f :: Env -> HStatement -> IOThrowsError HStatement
f env (If (cond, body)) = evalHVal env cond >>= \x -> case x of
Bool True -> return $ If (Bool True, body)
Bool False -> return $ If (Bool False, body)
The error I receive is the following : Couldn't match expected type ‘HStatement’ with actual type ‘[HStatement]’ at the guard line. I believe the reason as to why the first section of code was successful was because the values were being drawn from List but in the second case although they're being drawn from a list, they're being drawn from a [HStatement], not something that just represents a list...if that makes any sort of sense, I feel like I'm missing the vocabulary.
In essence then what should occur is given a selection block of n statement, a subset of these are produced whose guards are true and only one statement is taken from it.
The error message is pretty clear now that you have some types written down. g returns IOThrowsError [HStatement], so when you bind its result to x in h, you have an [HStatement]. You then call fstIf, which expects a single HStatement, not a list. You need to decide how to handle the multiple results from g.

Extracting values from list based on their type?

Im trying to iterate over a list of custom data types, and exact the value of a specific type. In this case, I want the ages from the list:
data MyData = Age Int | DOB Int | Name String | Address String
myList = [Age 89, DOB 13, Age 33, Name "Barbra", Address "103 Lane"]
myFunction :: [MyData] -> MyData
myFunction (x : xs) = if x == Age then x : myFunction xs else myFunction xs
Error:
"Age is applied to too few arguments"
Whats the best solution for this?
You can't really have x == Age ... that doesn't make sense. You can only compare x to other values of type MyData, like Age 10, or DOB 40, or Name "John". Age doesn't have type MyData ... it has type Int -> MyData.
You can check what constructor a value has by using case statements:
myFunction :: [MyData] -> MyData
myFunction (x:xs) = case x of
Age _ -> ...
DOB _ -> ...
Name _ -> ...
Address _ -> ...
Or if you only care about the Age constructor, you can wildcard everything else:
myFunction :: [MyData] -> MyData
myFunction (x:xs) = case x of
Age _ -> ...
_ -> ...
Also note that you might actually be wanting to return a [MyData], not a MyData.
For what it's worth, a nicer way to write this function might be
myFunction :: [MyData] -> [MyData]
myFunction xs = [ x | x#(Age _) <- xs ]
Or you can use a higher order function instead of explicit recursion, which tends to be more prone to bugs:
myFunction :: [MyData] -> [MyData]
myFunction = mapMaybe (\x -> case x of Age _ -> Just x; _ -> Nothing)
EDIT: Be careful of the language you're using here in the question -- all values of x have the same type, here -- MyData. Age 10 has the same type as DOB 40. They are all values of the same type, just created using different constructors. So this isn't filtering a list for values of a certain type -- it's filtering it for values created by a certain constructor.

Concatenating strings together into a list

What I'm trying to do is that I want to take a list of strings as input and do some operations then return back a list of strings. The problem is, I am looking for specific yet generic patterns of the string for each case:
func :: [String] -> [String]
func [] = []
func [x] = [x]
func (["Not","(","Not"]:es:[")"]) = es --HERE
func ("Not":"(":pred:"And":rest:")") = ("Not":pred:"Or":(pushNotInwards rest))
func ("Not":"(":pred:"Or":rest:")") = ("Not":pred:"And":(pushNotInwards rest))
func ("Not":"(":"ForAll":x:scope:")") = ("Exists":"Not":"("scope:")")
func ("Not":"(":"Exists":x:scope:")") = ("ForAll":"Not":"(":scope:")")
For the third case for instance, I want to take a list of strings in the form of:
["Not","(","Not",some_strings,")"]
I tried using ++ on the left hand side as:
func (["Not"]++["("]++["Not"])++es++[")"]) = es
I also tried concat and : but they didn't work either. Any suggestions?
You seem to have some confusion about the different string operators.
A String is just a synonym for a list of chars i.e. [Char]. The colon : operator (aka cons) adds one element to the beginning of a list. Here's its type:
*Main> :t (:)
(:) :: a -> [a] -> [a]
For example:
*Main> 1:[2,3]
[1,2,3]
*Main> 'a':"bc"
"abc"
The ++ operator concatenates two lists. Here's its type:
*Main> :t (++)
(++) :: [a] -> [a] -> [a]
Pattern matching can only be done using a data constructor. The : operator is a data constructor, but the ++ operator is not. So you cannot define a function using pattern matching over the ++ operator.
To define a function using pattern matching, I'd suggest defining a new data type for the different functions and qualifier rather than using strings:
-- Logic Operation
data LogicOp =
Not LogicOp | And [LogicOp] | Or [LogicOp] |
Forall String LogicOp | Exists String LogicOp | T | F
deriving (Eq, Show)
func :: LogicOp -> LogicOp
func (Not (Not x)) = x
func (Not (And (pred:rest))) = Or (Not pred:[func (Not (And rest))])
func (Not (Or (pred:rest))) = And (Not pred:[func (Not (Or rest))])
func (Not (Forall x scope)) = Exists x (Not scope)
func (Not (Exists x scope)) = Forall x (Not scope)
func x = x
Here are some examples:
*Main> func (Not (Not T))
T
*Main> func (Not (And [T, F, T]))
Or [Not T,Or [Not F,Or [Not T,Not (And [])]]]
*Main> func (Not (Or [T, F, T]))
And [Not T,And [Not F,And [Not T,Not (Or [])]]]
*Main> func (Not (Forall "x" (And T F))
*Main> func (Not (Forall "x" (And [T, F])))
Exists "x" (Not (And [T,F]))
*Main> func (Not (Exists "x" (And [T, F])))
Forall "x" (Not (And [T,F]))
You should probably not use strings for that. Create a new type:
data SomeExpr = Not SomeExpr
| And SomeExpr SomeExpr
| Or SomeExpr SomeExpr
deriving (Show)
Then you could match on that expression:
func :: SomeExpr -> SomeExpr
func (Not (Not x)) = func x
func (Not (And x y)) = Or (Not $ func x) (Not $ func y)
func (Not (Or x y)) = And (Not $ func x) (Not $ func y)
...
func x = x
You can't pattern match a list in the middle, e.g You want to match [1,2,3,4,5] with (1:middle:5:[]), but this is invalid.
Yes, using an own type has it's own problems, you have to parse it etc, but it is much more easier and safer than with strings (which could have arbitrary content).

manual Instance Show definition causes Stack Space Overflow

When I write manually a simple show instance for the PhisicalCell datatype, the program consumes all the space. When deriving his own version of Show, this doesn't happen. Why?
here is a stripped-down version of the code I'm writing:
import Data.Array
type Dimensions = (Int, Int)
type Position = (Int, Int)
data PipeType = Vertical | Horizontal | UpLeft | UpRight | DownLeft | DownRight deriving (Show)
data PhisicalCell = AirCell
| PipeCell PipeType
| DeathCell
| RecipientCell Object
-- deriving (Show) SEE THE PROBLEM BELOW
data Object = Pipe { pipeType :: PipeType -- tipo di tubo
, position :: Position -- posizione del tubo
, movable :: Bool -- se posso muoverlo
}
| Bowl { position :: Position -- posizione dell'angolo in alto a sinistra
, dimensions :: Dimensions -- dimensioni (orizzontale, verticale)
, waterMax :: Int -- quanta acqua puo' contenere al massimo
, waterStart :: Int -- con quanta acqua parte
, hatch :: Maybe Position -- un eventuale casella di sbocco
, sourceIn :: [Position] -- posti da cui l'acqua entra
, movable :: Bool -- se posso muoverlo
}
| Death
deriving (Show)
data Level = Level Dimensions [Object]
type LevelTable = Array Dimensions PhisicalCell
-- HERE IS THE PROBLEM --
instance Show PhisicalCell where
show AirCell = " "
show (PipeCell _) = "P"
show DeathCell = "X"
show (RecipientCell _) = "U"
both :: (a -> b) -> (a,a) -> (b,b)
both f (a,b) = (f a, f b)
levelTable :: Level -> LevelTable
levelTable (Level dim _) = initial
where initial = array ((0,0), both (+1) dim) $
[((x,y), AirCell) | x <- [1..fst dim], y <- [1..snd dim] ]
++ [((x,y), DeathCell) | x <- [0..fst dim + 1], y <- [0, snd dim + 1]]
++ [((x,y), DeathCell) | x <- [0, fst dim + 1], y <- [0..snd dim + 1]]
main = print $ levelTable (Level (8,12) [])
The Show type class has mutually referencing default implementations:
class Show a where
-- | Convert a value to a readable 'String'.
--
-- 'showsPrec' should satisfy the law
-- ...
...
showsPrec _ x s = show x ++ s
show x = shows x ""
showList ls s = showList__ shows ls s
...
shows :: (Show a) => a -> ShowS
shows = showsPrec 0
So if you declare a Show instance without defining any of the methods
instance Show where
nextNewFunction :: Bla
...
GHC will happily compile all the default ones, so there won't be any errors. However, as soon as you try to use any of them, your trapped in a loop as deadly as your Objects... and the mutual recursion will eventually blow the stack.
Now, your code doesn't quite look as if you have such an empty instance Show declarion, but in fact you do: because of the wrong indentation, the show you define there is recognised as a new free top-level function that merely happens to have the same name as GHC.Show.show. You could add
show :: PhisicalCell -> String
to your file and get the same result as now.
The problem does actually lie in the spacing that Sassa NF points out. When I indent the show, it works (and when I don't, I get the stack overflow). Without the indent, you're defining a top-level show function that is never used, and the show function for the Show instance of PhisicalCell has an undefined show function, which causes the problem.

Resources