How to use Value constructors to create records in PureScript - adt

I am attempting to create a record based on an array of data, the function looks like this:
type Address = {
street :: String,
city :: String,
state :: String
}
convertToAddress :: Array String -> Maybe Address
convertToAddress [street, city, state] = Just (Address { street: street, city: city, state: state })
convertToAddress _ = Nothing
Here, I am trying to create a Record of the type Address using the Address value constructor but it throws an error when compiling:
Unknown data constructor Address

type only defines a type alias, so Address and
{
street :: String,
city :: String,
state :: String
}
Are actually the same type. If you want to generate a constructor you will have to use newtype:
newtype Address = Address {
street :: String,
city :: String,
state :: String
}
Or alternatively, you can just get rid of the constructor in your code and just use the record type:
convertToAddress :: Array String -> Maybe Address
convertToAddress [street, city, state] = Just { street: street, city: city, state: state }
convertToAddress _ = Nothing

Related

What is the name of this elm construct: type X = X {...}?

I am trying to understand this Elm construct:
type Item = Item { name : String, data : String }
It resembles a record, but it behaves very differently.
It is useful for defining recursive data models.
Unlike type alias Item = {...}, it does not provide a "constructor".
I cannot find it in Elm Syntax guides.
I cannot figure out how to access its fields:
> item = Item { name = "abc", data = "def" }
Item { name = "abc", data = "def" } : Repl.Item
> item.name
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
`item` does not have a field named `name`.
6| item.name
^^^^^^^^^ The type of `item` is:
Item
Which does not contain a field named `name`.
How is this construct called?
How do you access the contained fields?
It is a Union Type with a single constructor which happens to take a Record as its only type parameter.
The fact that the type name and constructor name are both Item is a common idiom, but holds no significance. It could easily be any other valid constructor name:
type Item = Foo { name : String, data : String }
For practical purposes, it can be useful to use a type alias for the internal record type so you can more succinctly pull values out. If you move things around a little bit:
type alias ItemContents = { name : String, data : String }
type Item = Item ItemContents
You could provide a function that returns the internal contents:
getItemContents : Item -> ItemContents
getItemContents (Item contents) = contents
And now it could be used like this REPL example:
> item = Item { name = "abc", data = "def" }
Item { name = "abc", data = "def" } : Repl.Item
> contents = getItemContents item
{ name = "abc", data = "def" } : Repl.ItemContents
> contents.name
"abc" : String

How to fix this Purescript error: Could not match {...} with (...)?

I have a state for a halogen component including a lens like this:
import Optic.Core (Lens', lens)
type State =
{ userName :: String
, password :: String
, formError :: String
}
_userName :: Lens' State String
_userName = lens _.userName (\r str -> r { userName = str })
And I want to modify the state in the eval function of the same component like this:
eval :: forall eff.
Query ~> ParentDSL State Query UserNameField.Query Slot Void (Aff (console :: CONSOLE , ajax :: AJAX | eff))
eval = case _ of
HandleInput userName next -> do
-- this code causes trouble:
_userName .= userName
-- while this code works:
-- modify (set _userName userName)
pure next
However, I get the error message:
Could not match type
{ userName :: String
, password :: String
, formError :: String
}
with type
( userName :: String
, password :: String
, formError :: String
)
while trying to match type t3
{ userName :: String
, password :: String
, formError :: String
}
with type t2
while checking that expression _userName
has type (t0 -> t1) -> t2 -> t2
in value declaration eval
where t1 is an unknown type
t0 is an unknown type
t2 is an unknown type
t3 is an unknown type
[TypesDoNotUnify]
Note the difference between { and ( (took me a while). I don't even know what the latter type actually means and I have no clue why this error is introduced by a MonadState-based lense.
Mystery solved: I unintentionally mixed two packages
purescript-lens and purescript-profunctor-lenses. My lenses came from the former and the assign function (.=) is only present in the latter, which was installed apparently as some implicit subdependency.

Making constant global variables of a custom struct type

I want to create a "class" to handle the input validation. I first make a type of Input which is a string for storing user input and a type of REGP which store the regex pattern and the description of the pattern. I created two constant instances REGP_LOGINNAME and REGP_PASSWORD. But I get error of const initializer REGP literal is not a constant. Why?
package aut
import "regexp"
type Input string
type REGP struct {
pattern string
Descr string
}
const REGP_LOGINNAME = REGP{ //const initializer REGP literal is not a constant
"regex pattern 1",
"regex description 1",
}
const REGP_PASSWORD = REGP{ //const initializer REGP literal is not a constant
"regex pattern 2",
"regex description 2",
}
func (i Input) isMatch(regp REGP) bool {
isMatchREGP, _ := regexp.MatchString(regp.pattern, string(i))
return isMatchREGP
}
Error Message:
/usr/local/go/bin/go build -i [/home/casper/gopath/codespace_v2.6.6/dev/server_side/golang/go_codespace_v2.1/server/lib/aut]
# _/home/casper/gopath/codespace_v2.6.6/dev/server_side/golang/go_codespace_v2.1/server/lib/aut
./validation.go:15: const initializer REGP literal is not a constant
./validation.go:20: const initializer REGP literal is not a constant
Error: process exited with code 2.
Consants in Go can only be scalar values (eg. 2, true, 3.14, "and more") or any expression that is composed of only constants (eg. 1 + 2, "hello " + "world", or 2 * math.Pi * 1i).
This means that struct types such as your REGP_LOGINNAME which are not scalar values cannot be assigned to constants. Instead, use a variable:
var (
REGP_LOGINNAME = REGP{
pattern: `/^(?=^.{6,20}$)^[a-zA-Z][a-zA-Z0-9]*[._-]?[a-zA-Z0-9]+$/`,
Descr: "regex description 1",
}
REGP_PASSWORD = REGP{
pattern: `/^(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!##$%^&*()]*$/`,
Descr: "regex description 2",
}
)
Further Reading
https://blog.golang.org/constants
Aside: I don't know your use case, of course, but I really really doubt you actually need or want to use a regexp to validate a users password. Instead, consider passing it through the OpaqueString profile of PRECIS (a framework for handling and enforcing safety of unicode strings; the opaque string profile was designed to handle passwords). Similarly, the UsernameCaseMapped and UsernameCasePreserved profiles (also implemented in the linked package) can be used for usernames to ensure you don't end up with two usernames that look the same but have different unicode characters in them. Further validation can also be done, of course.
I finally find that it seems not possible to make the REGP pointer or its variable inside to be constant. So I just make them global variables.
package aut
import "regexp"
type Input string
type REGP struct {
pattern string
Descr string
}
var REGP_LOGINNAME = REGP{
pattern: "/^(?=^.{6,20}$)^[a-zA-Z][a-zA-Z0-9]*[._-]?[a-zA-Z0-9]+$/",
Descr: "regex description 1",
}
var REGP_PASSWORD = REGP{
pattern: "/^(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!##$%^&*()]*$/",
Descr: "regex description 2",
}
func (i Input) isMatch(regp REGP) bool {
isMatchREGP, _ := regexp.MatchString(regp.pattern, string(i))
return isMatchREGP
}

Records in PureScript

I don't quite understand why this works:
module Records where
type Element e = { element :: String, label :: String | e }
type Sel = ( value :: Number, values :: [Number] )
type Select = Element Sel
while this says Cannot unify # * with *.
module Records where
type Element e = { element :: String, label :: String | e }
type Sel = { value :: Number, values :: [Number] }
type Select = Element Sel
(Note the '()' around the right hand side of Sel instead of the '{}'.)
I've read here https://leanpub.com/purescript/read#leanpub-auto-objects-and-rows that forall r. { firstName :: String, lastName :: String | r } desugars to
forall r. Object (firstName :: String, lastName :: String | r)
I'm still a bit confused, why you can't use the record-sugar for extending records.
The Object type constructor is parameterized by a row of types. In kind notation, Object has kind # * -> *. That is, it takes a row of types to a type.
( value :: Number, values :: [Number] ) denotes a row of types (something of kind # *), so it can be passed to Object to construct a type, namely
Object ( value :: Number, values :: [Number] )
Note that { ... } is just syntactic sugar for the Object type constructor, so this is the same as
{ value :: Number, values :: [Number] }
Both have kind *, so it doesn't make sense to pass this thing as an argument to Element, since the type variable e in Element has kind # *.
Put another way, Element Sel in your second example unrolls to
{ element :: String, label :: String | { value :: Number, values :: [Number] } }
which desugars to
Object (element :: String, label :: String | Object (value :: Number, values :: [Number]) )
which fails to kind-check due to the thing of kind * in the tail of the outer row.

Initializing an array of UDT in VB6

I have declared an UDT and I need to initialise an array with specific records of the UDT, how would I do it at the module level.
Here is what I've tried
Public Type MyType
id As Integer
name As String
values As Double
End Type
private MY_TYPES(1) As MyType
My_TYPES(0) = newMyType(1, "Item 1", 15.9)
My_TYPES(1) = newMyType(2, "Item 2", 30.2)
Private Function newMyType(byval id as Integer, byval name as String, _
byval v as Double) As MyType
Dim t As MyType
t.id = id
t.name = name
t.value = v
newMyType = t
End Function
The error I get is Invalid outside procedure
As you can see it I try to reproduce what would be static initialization of a java Collection like a List or Set
I would like to expose the collection as constant, how could I achive this?
you have to place the following 2 lines in a sub, and then call the sub to init the udt
My_TYPES(0) = newMyType(1, "Item 1", 15.9)
My_TYPES(1) = newMyType(2, "Item 2", 30.2)
or you can can place these 2 lines in the working sub inside an if..then with a module level init boolean

Resources