A defined data type not defined? - haskell

I need some help trying to understand why these definitions
data SegmentList
= SegmentList SegmentlistHeader [Segment]
| AugmentedSegmentList SegmentlistHeader [AugmentedSegment]
deriving (Show)
data SegmentlistHeader
= SegmentlistHeader DatabaseName Query LabelType TimeStamp
deriving (Show)
data Segment
= Segment SegmentLabel SegmentStart SegmentEnd Session Checksum
| AugmentedSegment SegmentLabel SegmentStart SegmentEnd Session Checksum Metadata
deriving (Show)
type DatabaseName = String
type SegmentLabel = String
type SegmentStart = Double
type SegmentEnd = Double
type Session = String
type LabelType = String
type Query = String
type TimeStamp = String
type Checksum = String
type Metadata = [(String, String)]
result in this error message:
Not in scope: type constructor or class `AugmentedSegment'
A data constructor of that name is in scope; did you mean -XDataKinds?
while this :
data UmeQueryPart
= LabelInLabelType String [String] String
| LabelType String
| UmeQueryDominance UmeQueryPart UmeQueryPart String
| UmeQuerySequence UmeQueryPart UmeQueryPart String
| UmeQueryIntersect [UmeQueryPart]
| UmeQueryUnion [UmeQueryPart]
deriving Show
compiles like a charm. I'm obviously not skilled enough to see the difference...

From your edit, you have
data SegmentList
= SegmentList SegmentlistHeader [Segment]
| AugmentedSegmentList SegmentlistHeader [AugmentedSegment]
deriving (Show)
data Segment
= Segment SegmentLabel SegmentStart SegmentEnd Session Checksum
| AugmentedSegment SegmentLabel SegmentStart SegmentEnd Session Checksum Metadata
deriving (Show)
The problem specifically is from the second constructor of SegmentList:
AugmentedSegmentList SegmentlistHeader [AugmentedSegment]
Here you've said that AugmentedSegmentList contains a list of AugmentedSegment, but AugmentedSegment is a constructor of Segment, it is not a type. When defining a data type, it can only reference other types, not other constructors. You could change it to
AugmentedSegmentList SegmentlistHeader [Segment]
But this probably isn't exactly what you want. Since your Segment and AugmentedSegment constructors are identical other than the addition of the Metadata field, I would instead recommend having
data Segment
= Segment SegmentLabel SegmentStart SegmentEnd Session Checksum
deriving (Show)
data AugmentedSegment
= AugmentedSegment Segment Metadata
deriving (Show)
Then you can have a list of only AugmentedSegments which is enforced by the type system, but it also means that you can't pass in an AugmentedSegment to a function that accepts a Segment. Since these appear to be different things, this shouldn't be a problem. If it is, you can always just pass in the contained Segment field from an AugmentedSegment into the function you're concerned with, or you can alter your function to accept a value of type Either Segment AugmentedSegment instead.
In summary, when you have something like
data MyType = MyConstructor FieldA FieldB FieldC
The MyType symbol is the name of the type, the MyConstructor symbol is a constructor, you can think of it as a function that returns something of type MyType, and the FieldNs symbols all have to be existing types or can recursively refer to MyType, they can not be other constructors. This is what caused the error you're seeing.

Related

Same variable name in Data types

Why using data types I cannot give same inner attribute name for those Data attributes?
Here I cannot reuse the variable name val in several Data
Does not compile
data Product = Product {val::String}deriving (Show, Eq)
data Price = Price {val::Double}deriving (Show, Eq)
data Discount = Discount { val::Double }deriving (Show, Eq)
compile
data Product = Product {productVal::String}deriving (Show, Eq)
data Price = Price {priceVal::Double}deriving (Show, Eq)
data Discount = Discount { discountVal::Double }deriving (Show, Eq)
Why using data types I cannot give same inner attribute name for those Data attributes?
If you define a record type, you implicitly have constructed a "getter". If you define a record datatype like:
data Product = Product { val :: String } deriving (Show, Eq)
then Haskell will construct a function:
val :: Product -> String
that obtains the val of a given Product object.
If you then later define a new record datatype:
data Price = Price { val :: Double } deriving (Show, Eq)
then you thus define two versions of val, which thus results in name clashes.
The DuplicateRecordFields extension
The Glasgow Haskell Compiler (GHC) has, since 8.0.1, an extension DuplicateRecordFields that allows to specify two record datatypes with the same field name.
There is no problem to use the same record name for pattern matching, or when we construct records, for example:
productToPrice :: Product -> Price
productToPrice (Product {val = x}) = Price { val = 3 }
creates no problems, since val in Product { val = x } clearly refers to the val defined in the Product data constructor, and val in Price { val = 3 } refers to the val of the Price data constructor.
If we however use val as a function, it will create ambiguity:
Prelude> val (Product "foo")
<interactive>:15:1: error:
Ambiguous occurrence ‘val’
It could refer to either the field ‘val’,
defined at <interactive>:1:25
or the field ‘val’, defined at <interactive>:2:21
We can add the signature of the function to specify which val we want to use:
Prelude> (val :: Product -> String) (Product "foo")
"foo"
or by specifying the type of Product "foo", we obtain the same effect:
Prelude> val (Product "foo" :: Product)
"foo"
Given val however has the same type, or has some generic meaning, it might be better to introduce a typeclass, and thus define the val function there.

Haskell : recursive data type (Parameterized Types)

I have this :
data Val s i a = S s | I i | A a deriving (Show)
To play with non-homogenous lists in Haskell. So I can do something like (just an example function ):
oneDown :: Val String Int [String]-> Either String String
But I would actually like this to be a list of Vals, i.e. something like :
oneDown :: Val String Int [Val]-> Either String String
What you're looking for would result in an infinite data type, which Haskell explicitly disallows. However, we can hide this infinity behind a newtype and the compiler won't complain.
data Val s i a = S s | I i | A a deriving (Show)
newtype Val' = Val' (Val String Int [Val']) deriving (Show)
It's still doing exactly what your example did (plus a few type constructors that will get optimized away at runtime), but now we can infinitely recurse because we've guarded the recursive type.
This is actually what the recursion-schemes library does to get inductively-defined data that we can define generic recursion techniques on. If you're interested in generalized data types like this, you may have a look at that library.
To construct this newly-made type, we have to use the Val' constructor.
let myVal = A [Val' (I 3), Val' (S "ABC"), Val' (A [])]

Executing Parsed function calls in Haskell

First i want to say I'm a newbie in Haskell. Here's my problem:
For a school project I need to be able to parse and interprate and execute a fucntion call. This call needs to be able to execute a function already defined in haskell.
Parsing the call works, but i have no idea how to execute the function because the amount of arguments and type is unkown.
Here is how i represent my data
type Name = String
type Cond = Expr
data Expr
= Num Int
| Boolean Bool
| BinOp Op Expr Expr
| Var Name
deriving (Eq, Ord, Show)
data Stmnt
= Call Name [Expr]
| If Cond [Stmnt] [Stmnt]
| While Cond [Stmnt]
| VarDef Name Expr
deriving (Eq, Ord, Show)
This is a part of my interpeter. And it is with the implementation of funcall that I need help.
data Value = FineInt Int
| FineBool Bool
| FineFun ([Value] -> Value)
-- The enviroment keeps track of variables in the program
type Env = [(Name,Value)]
-- A state that takes an enviroment
type StEnv = State Env
evalstm :: Stmnt -> StEnv ()
evalstm (Call name exprs) = funcall name exprs
-- funcall name exprs = ?

Generic type for OO classes in Haskell

I want to have a generic type that can represent any class in a simple class diagram. In this case a class contains:
A name
Any number of arguments of any type
Any number of functions that takes any number of arguments of any type
I have only used simple ADT declarations which is not working in this case, for example this is what I have been stuck with but it gives me no where near the type of flexibility I'm after:
data Attr a = Attr { name :: String
, kind :: a}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr Int]}
deriving (Show)
data Class a = NewC { name2 :: String
, attrs :: [Attr Int]
, actions :: [Action]}
deriving (Show)
So my question is now how would I go about representing any arbitrary class in Haskell?
I do not want to do OOP in haskell. Imaging that the class type I'm trying to make will be a node in a graph. However each node in the graph will be a different class.
I think you want to represent your class diagrams entirely as values rather than a mix of values and types. Instead of Attr Int, for example, you might use something like Attr { name="Int", kind=PrimitiveInt }. I've introduced an OopType type below.
data Attr = Attr { name :: String
, kind :: OopType}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr]}
deriving (Show)
data Class = NewC { name2 :: String
, attrs :: [Attr]
, actions :: [Action]}
deriving (Show)
data OopType = ClassType Class
| InterfaceType Class -- TODO make a dedicated interface type
| Enum -- TODO make a dedicated enum type
| PrimitiveString
| PrimitiveInt
Note that this representation doesn't model 'generics' (that is, classes that are parameterised by types). To do that, you'd add another field to the Class type.

Haskell data type

Let's say that I have a type like this (that works):
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE -- This works, but I want to define it as below
deriving(Eq, Read, Show)
I want a type like this (doesn't work):
data WAE = Num Float
| Id String
| With [(Id, WAE)] WAE -- This doesn't work ("Id not in scope")
deriving(Eq, Read, Show)
Why can't I do that in Haskell? Any ideas in achieveing a similar effect?
In Haskell, there are two distinct namespaces. One for values, and one for types. Data constructors such as Id live in the value namespace, whereas type constructors such as String, as well as classes live in the type namespace. This is OK because there is no context where both would be allowed.
In the definition of a data type, the two namespaces live side by side, as you're defining a both a new type constructor and several new data constructors, while referring to existing type constructors.
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE
deriving(Eq, Read, Show)
Here, WAE, Float, String, (,), [], Eq, Read and Show are all names in the world of types, whereas Num, Id and With are names in the world of values. Mixing them does not make any sense, and this is why Id is not in scope in your second piece of code, as you are in a type context, and there is no type-level thing called Id.
It's not 100% clear from your question what you were trying to do, but I suspect it might be something like this:
type Id = String -- Or perhaps a newtype
data WAE = Num Float
| Id Id
| With [(Id, WAE)] WAE
deriving(Eq, Read, Show)
Note that because the namespaces are distinct, it's perfectly fine to have something called Id in both.
Based on your question, I'm not entirely sure what you are trying to accomplish. Here are two possibilities that are possible with Haskell's type-system.
data WAE = Num Float
| Id String
| With [(WAE, WAE)] WAE
deriving (Eq, Read, Show)
I'm not sure this is what you want, however, because it allows for more than just an id in the first portion of the pair.
Another possibility is to create a new type (or alias) for the id, like so:
data MyId = MyId String deriving (Eq, Read, Show)
data WAE = Num MyId Float
| Id MyId
| With [(MyId, WAE)] WAE
deriving (Eq, Read, Show)
Note that MyId could also be created with either newtype or type, each giving a slightly different meaning.
You cannot, however use Id as it is a data-constructor, where a type is expected.
Here:
| With [(Id, WAE)] WAE
you are using a data constructor Id in a context where a type is expected. The type of Id is WAE, so if you change this line to:
| With [(WAE, WAE)] WAE
it will compile, but the result is probably not what you want.
If you just want to show that the string in question is an identifier semantically, you can use a type alias:
type Id = String
data WAE = Num Float
| Id Id
| With [(Id, WAE)] WAE
deriving(Eq, Read, Show)

Resources