Haskell cannot define function as part of record? - haskell

I would like to define a data type that is a record with one function named f:
data A = A { f :: Int -> Int }
and I would like to create an instance:
A {f x = x * 2 }
However: this gives a syntax error:
error: parse error on input ‘x’

The following is the grammar for constructions using field labels.
aexp → qcon { fbind1 , … , fbindn } (labeled construction, n ≥ 0)
fbind → qvar = exp
Note that qcon is a constructor syntax, qvar is a variable syntax, and exp is an expression syntax.
The reason A {f x = x * 2} does not work therefore is because it is invalid syntax. A syntax that is valid and that is probably what you want is A {f = \x -> x * 2}. Alternatively, A {f = (* 2)}, A {f = (2 *)}, or A {f = (*) 2}.
Construction using field labels operates like named parameters. Given a data type definition such as
data Person = Person { name :: String, age :: Int }
The expression
Person { age = 65, name = "Wilbur Suidae" }
Means
Person "Wilbur Suidae" 65
That is, the constructor arguments are ordered to match the order of fields according to the constructor definition.
The expression
Person { age = 65 }
Means
Person undefined 65
That is, if a field is not explicitly assigned a value it is implicitly assigned the value undefined.
References
Construction Using Field Labels, § 3.15.2, Haskell Report 2010

Related

How to limit a Int field to a range of values?

In my Data
data User = User { uRank :: Int, uProgress :: Int }
I want to limit uRank to a list of values [-1, 1, 3], for example.
How do I do this?
Defining a small sum type is the best answer for this specific question. You can also use newtype with smart constructors to achieve this effect.
newtype Rank = UnsafeMkRank { unRank :: Int }
mkRank :: Int -> Maybe Rank
mkRank i
| i `elem` [-1, 1, 3] = Just (UnsafeMkRank i)
| otherwise = Nothing
Now, provided you only use the safe mkRank constructor, you can assume that your Rank values have the Int values you want.
For something so small, you should define a precise type:
data Rank = RankNegOne | RankOne | RankThree -- There are probably better names
data User = User { uRank :: Rank, uProgress :: Int }
Haskell doesn't force you to encode everything as a subset of the integers; take advantage of it!
For larger subsets where this would be unwieldy, you are looking for a dependent type, which (until recently?) is not supported by Haskell directly.
Liquid Haskell, which adds refinement types on top of Haskell, can do this. See the correct section of the tutorial here.
First you define your data type as normal.
module User where
data User = User { uRank :: Int
, uProgress :: Int
}
Next we define your restriction as a refinement type. Liquid Haskell users comment annotations with syntax {-# blah #-}. We'll define your odd restriction of -1, 1, 3 first with the RestrictedInt type:
{-# type RestrictedInt = {v : Int | v == -1 || v == 1 || v == 3} #-}
That is, the RestrictedInt is an Int that is either -1, 1, or 3. Notice you could easily write ranges and other restrictions, it doesn't have to be some mindless enumeration of legitimate values.
Now we re-define your data type in our refinement language using this restricted int type:
{-# data User = User { uRank :: RestrictedInt
, uProgress :: Int }
#-}
This is similar to your definition but with the restriction type instead of just Int. We could have inlined the restriction instead of having a type alias but then your User data type would be pretty unreadable.
You can define good values and the liquid tool will not complain:
goodValue :: User
goodValue = User 1 12
But bad values result in an error:
badValue :: User
badValue = User 10 12
$ liquid so.hs (or your editor's integration, if you have that setup) produces:
**** RESULT: UNSAFE ************************************************************
so.hs:16:12-18: Error: Liquid Type Mismatch
16 | badValue = User 10 12
^^^^^^^
Inferred type
VV : {VV : GHC.Types.Int | VV == ?a}
not a subtype of Required type
VV : {VV : GHC.Types.Int | VV == (-1)
|| (VV == 1
|| VV == 3)}
In Context
?a := {?a : GHC.Types.Int | ?a == (10 : int)}

Type casting when working with nested data structures

I have the following data structures defined:
data Operator = Plus | Times | Minus deriving (Eq,Show)
data Variable = A | B | C deriving (Eq,Show)
newtype Const = D Numeral deriving (Eq,Show)
data CVO = Const | Variable | Operator deriving (Eq,Show)
type Expr = [CVO]
I have defined the following function:
eval2 :: Expr -> Integer
eval2 x = helper x
I would like to check if an element of the CVO list (Expr) is either an instance of Const, Variable or Operator (this works) and I would like to implement varying code for the specific type of the instance (e.g. Plus, Times, Minus for Operator).
helper :: Expr -> Integer
helper [] = 2
helper (x:xs)
| x == Operator && x == Plus = 1
I cannot compare x to Plus, because it expects x to be of type CVO.
Couldn't match expected type ‘CVO’ with actual type ‘Operator’
Is it somehow possible to cast x to be an instance of Operator in order to do the comparison?
A value can't have two different types at the same time. If x is a CVO you can't use == to compare it to Plus which is an Operator.
At the moment the type CVO consists of three constant values called Const, Variable and Operator. I'm guessing you actually wanted it to contain values of the type Const, Variable or Operator. You do that by declaring arguments to the constructors.
data CVO = Const Const -- a constructor whose name is Const and contains a value of type Const
| Var Variable -- a constructor named Var containing a Variable
| Op Operator -- a constructor named Op containing an Operator
A given value of type CVO must have been built from one of those three constructors, containing a value of the correct type. You can test which constructor was used to create the CVO, and simultaneously unpack the value, using pattern matching. Something like this:
helper :: Expr -> Integer
helper [] = 0
helper (Op o:xs) -- because we matched Op, we know o :: Operator
| o == Plus = 1
| otherwise = 2
helper _ = 3

Haskell - Type conversion?

I'm trying to convert data from a list, 'profile1', into a custom type called 'DataSubject'.
I'm passing this to a function 'makeDS' to attempt this conversion - however the following isn't working:
type Name = String
type Age = Int
type Iq = Int
type Language = String
data DataSubject = DS {name :: Name, age :: Age, iq :: Iq, language :: Language} deriving (Show)
data Contain = Name String | Age Int | Iq Int | Language String deriving (Show) --Use so list can take multiple types
profile1 = [Name "Bob", Age 22, Iq 100, Language "French"]
makeDS :: [Contain] -> DataSubject
makeDS t = DS {name = t!!0, age = t!!1, iq = t!!2, language = t!!3}
main = do
let x = makeDS profile1
putStrLn $ show x
Error:
Couldn't match type ‘Contain’ with ‘[Char]’
I'm just getting started with Haskell - could someone advise on my error? And if there's better ways of doing this?
In the definition of makeDS, the variable t is of type [Contain] (i.e. a list of Contain), so when you say t!!0 this will extract the first element of that list, which has type Contain. The problem is that the name field of DataSubject contains a String (which is an alias of [Char]). So you are trying to store a Contain in the place of [Char], which is not possible because the types are different. You need a different approach in you code.
One issue is that every single Contain value represents a single field of DataSubject. So if we are given a list of Contain, there is no guarantee that the values will be given in a specific order (e.g. Name first, followed by Age, etc) or even that all fields are provided. Even if you always provide all fields in a specific order in your code as convention, haskell cannot possibly know that. One solution that does not depend on order is to try to "build" the DataSubject object step-by-step, by starting with an "empty" DataSubject and then examining the list of Contain and adding the corresponding DataSubject field:
makeDS :: [Contain] -> DataSubject
makeDS = foldr updateDS emptyDS
where
updateDS (Name s) ds = ds {name = s}
updateDS (Age n) ds = ds {age = n}
updateDS (Iq n) ds = ds {iq = n}
updateDS (Language s) ds = ds {language = s}
emptyDS = DS {name = "", age = 0, iq = 0, language = ""}
So here, I defined emptyDS which is an "empty" DataSubject object and a function called updateDS which take a (single) Contain and a DataSubject and updates the DataSubject based on the field specified by Contain and then it returns it. Finally, I use a fold to run repeatedly update the DataSubject (starting with emptyDS) using updateDS.
You have a type mismatch. You have a list of Contain. So when you use
t !! 0
you get a Contain, not a String, which is necessary for name in DS. You need a function Contain -> Name, e.g.
containToName :: Contain -> Name
containToName (Name xs) = xs
containToName _ = error "not a name"
However, that's a partial function, since containToName (Age 12) will lead to an error.
Note that this has nothing to do with typeclasses. Now, if you want to use profile1, one way would be to just use
profile1 :: DataSubject
instead of
profile1 :: [Contain]
e.g.
profile1 :: DataSubject
profile1 = DS "Bob" 22 100 "French"
After all, there's nothing in the type [Contain] that will make sure that you have all the ingredients for a complete DataSubject.
And if there's better ways of doing this?
That depends on what you want to do. If you just want to handle DataSubjects, don't use an temporary list of Contain. If you want to handle user input (or similar), it gets a little bit more tricky.
The declaration of DataSubject says that we need a Name for the name field. And Name is the same as String. So in the expression DS {name = t!!0, ...}, we need t !! 0 to return a String. However, t !! 0 returns an element of t, and t has type [Contain]. So t !! 0 has type Contain, which is different from String.
To fix this type error, you need to convert the Contain to a String, maybe so:
DS { name = case t !! 0 of Name s => s, ... }

Haskell does not support the C++ overloading style in which functions with different types share a common name

I am learning Haskell. When I gone through following documentation.
https://www.haskell.org/tutorial/classes.html
It is mentioned that "Haskell does not support the C++ overloading style in which functions with different types share a common name." I am not getting this statement, I guess ad-hoc polymorphism (which is done by using type classes) is equivalent to method overloading in C++, Java. Can some body explain me is my understanding correct ?
class Equal a where
isEquals :: a -> a -> Bool
type Id = Int
type Name = String
data Employee = Engineer Id Name
data Student = Student Id Name
getEmpId (Engineer empId _) = empId
getStudId (Student studId _) = studId
instance Equal Employee where
isEquals emp1 emp2 = getEmpId emp1 == getEmpId emp2
instance Equal Student where
isEquals stud1 stud2 = getStudId stud1 == getStudId stud2
In the above snippet 'isEquals' function is applied to two different types Employee, Student which is equivalant of overloading in C++, Java. Is my understanding correct?
Partially, yes. However, keep in mind that signature of your isEquals is always a -> a. In C++ you could easily write:
int foo(int a, int b)
int foo(int a, char b)
int foo(char a, char b)
By using typeclasses you're only able to get first and third function, never the second.
UPDATE 1:
as noted in comments, you can achieve the second version by using MultiParamTypeClasses extension (if you're using GHC). Still, there is fourth version:
int foo(int a, int a, int a)
which has wrong arity if you use a typeclass, but is perfectly fine in C++.
Type classes in Haskell are just a fancy way of providing implicit arguments. Consider this code:
data Equal a = Equal {isEquals :: a -> a -> Bool}
type Id = Int
type Name = String
data Employee = Engineer Id Name
data Student = Student Id Name
getEmpId (Engineer empId _) = empId
getStudId (Student studId _) = studId
equalEmployee :: Equal Employee
equalEmployee = Equal {
isEquals = \emp1 emp2 -> getEmpId emp1 == getEmpId emp2
}
equalStudent :: Equal Student
equalStudent = Equal {
isEquals stud1 stud2 = getStudId stud1 == getStudId stud2
}
equalThree :: Equal a -> a -> a -> a -> Bool
equalThree e a1 a2 a3 = isEquals e a1 a2 && isEquals e a2 a3
What is the difference with your code? Well, if in your code we define
equalThree :: Equal a => a -> a -> a -> Bool
equalThree a1 a2 a3 = isEquals a1 a2 && isEquals a2 a3
The difference is that in your code (with classes) compiler finds a suitable class instance by itself, using given types. In my variant, required instances are provided explicitly. But that's the only difference; in fact, your variant would be converted to mine under the hood.
So, classes do not override anything. They are just a fancy syntax for data types and implicit arguments.
Not really. The only way to get the equivalent of C++ (function; Haskell has no methods!) overloading would be a type class
class SomeFunc a where
someFunc :: a
Now you can define someFunc at (more or less) any type you want. But you would have to declare it for every function you want to 'overload', whereas in C++ it's implicit simply from having two functions with the same name.
Haskell's type system is designed to provide something C++'s doesn't: standardized behavior (expressed as laws). So, for example, the standard Prelude defines
class Eq a where
(==), (/=) :: a -> a -> Bool
and now you know every == operator in the language takes two arguments, of the same type, and returns a boolean; by contrast, C++ is perfectly fine with something like
mystring operator (==)(mystring x, string y) {
return x + " == " + y;
}
that breaks all of those 'reasonable' rules. Beyond that, type classes come with laws, e.g.
x == x = True -- x total
x == y = y == x
x == y = True => y == z = True => x == z = True
which are additional restrictions on all instances. That's made a lot easier by the fact that every instance is an instance of this type class (defined in one place), which gives you a single place to define what those laws are. In C++, such 'laws' have more of the character of conventions. Furthermore, C++ is explicitly designed to allow things like using + for string concatenation, while Haskell is explicitly designed to dis-allow things like that (that's what 'Haskell does not supporth the C++ overloading style' probably means), so laws have to have more of the character of conventions in C++, which individual types can ignore if it's convenient for them.

Is there a programming language that performs currying when named parameters are omitted?

Many functional programming languages have support for curried parameters.
To support currying functions the parameters to the function are essentially a tuple where the last parameter can be omitted making a new function requiring a smaller tuple.
I'm thinking of designing a language that always uses records (aka named parameters) for function parameters.
Thus simple math functions in my make believe language would be:
add { left : num, right : num } = ...
minus { left : num, right : num } = ..
You can pass in any record to those functions so long as they have those two named parameters (they can have more just "left" and "right").
If they have only one of the named parameter it creates a new function:
minus5 :: { left : num } -> num
minus5 = minus { right : 5 }
I borrow some of haskell's notation for above.
Has any one seen a language that does this?
OCaml has named parameters and currying is automatic (though sometimes type annotation is required when dealing with optional parameters), but they are not tupled :
Objective Caml version 3.11.2
# let f ~x ~y = x + y;;
val f : x:int -> y:int -> int = <fun>
# f ~y:5;;
- : x:int -> int = <fun>
# let g = f ~y:5;;
val g : x:int -> int = <fun>
# g ~x:3;;
- : int = 8
Sure, Mathematica can do that sort of thing.

Resources