Purescript Halogen Component function: Passing spaced arguments instead of a Record? - purescript

I'm on PureScript 0.8.2. In PureScript Halogen, the component function has the signature:
component :: forall s f g. ComponentSpec s f g -> Component s f g
where
-- | A spec for a component.
type ComponentSpec s f g =
{ render :: s -> ComponentHTML f
, eval :: Natural f (ComponentDSL s f g)
}
So component expects a record. But in the Halogen Template Project, component is called as follows:
ui = component render eval
Am I looking at two different component functions? or does arguments separated by space get converted into a record? So I tried the following in psci:
> type Point = { x :: Int, y :: Int }
> let
addP :: Point -> Int
addP p = p.x + p.y
> addP {x: 4, y: 5 }
9
> addP 4 5
Error found:
in module $PSCI
at line 1, column 1 - line 1, column 8
Could not match type
{ x :: Int
, y :: Int
}
with type
Int
....

Sorry, the template project hasn't been updated yet. Thanks for the reminder!
Assuming your eval and render functions are in scope you can use field puns to write the component definition this way:
ui = component { render, eval }
But yes, a record is always required now. I'll update the template project right away.

Related

API for handling polymothinc records

It is a little bit custom issue, is not contrived, but just simplified as possible.
-- this record that has fn that handles both x and y,
-- x and y supposed to be Functors, a arbitrary param for x/y, r is arbitrary result param
type R0 a x y r =
{ fn :: x a -> y a -> r
}
-- this record that has fn that handles only x
type R1 a x r =
{ fn :: x a -> r
}
What I want is a common API (function) that could handle values of R0 and R1 types.
So I do a sum type
data T a x y r
= T0 (R0 a x y r)
| T1 (R1 a x r)
And I declare this function, there is a constraint that x and y have to be Functors.
some :: ∀ a x y r.
Functor x =>
Functor y =>
T a x y r -> a
some = unsafeCoerce -- just stub
Then try to use it.
data X a = X { x :: a}
data Y a = Y { y :: a }
-- make X type functor
instance functorX :: Functor X where
map fn (X val) = X { x: fn val.x }
-- make Y type functor
instance functorY :: Functor Y where
map fn (Y val) = Y { y: fn val.y }
-- declare functions
fn0 :: ∀ a. X a -> Y a -> Unit
fn0 = unsafeCoerce
fn1 :: ∀ a. X a -> Unit
fn1 = unsafeCoerce
Trying to apply some:
someRes0 = some $ T0 { fn: fn0 } -- works
someRes1 = some $ T1 { fn: fn1 } -- error becase it can not infer Y which should be functor but is not present in f1.
So the question is: Is it possible to make such API work somehow in a sensible/ergonomic way (that would not require some addition type annotations from a user of this API)?
I could apparently implement different functions some0 and some1 for handling both cases, but I wonder if the way with a single function (which makes API surface simpler) is possilbe.
And what would be other suggestions for implementing such requirements(good API handling such polymorphic record types that differ in a way described above, when one of the records has exessive params)?
You should make T1 and T0 separate types and then make function some itself overloaded to work with them both:
data T0 x y r a = T0 (R0 a x y r)
data T1 x r a = T1 (R1 a x r)
class Some t where
some :: forall a. t a -> a
instance someT0 :: (Functor x, Functor y) => Some (T0 x y r) where
some = unsafeCoerce
instance someT1 :: Functor x => Some (T1 x r) where
some = unsafeCoerce
An alternative, though much less elegant, solution would be to have the caller of some explicitly specify the y type with a type signature. This is the default approach in situations when a type can't be inferred by the compiler:
someRes1 :: forall a. a
someRes1 = some (T1 { fn: fn1 } :: T a X Y Unit)
Note that I had to add a type signature for someRes1 in order to have the type variable a in scope. Otherwise I couldn't use it in the type signature T a X Y Unit.
An even more alternative way to specify y would be to introduce a dummy parameter of type FProxy:
some :: ∀ a x y r.
Functor x =>
Functor y =>
FProxy y -> T a x y r -> a
some _ = unsafeCoerce
someRes0 = some FProxy $ T0 { fn: fn0 }
someRes1 = some (FProxy :: FProxy Maybe) $ T1 { fn: fn1 }
This way you don't have to spell out all parameters of T.
I provided the latter two solutions just for context, but I believe the first one is what you're looking for, based on your description of the problem mentioning "polymorphic methods". This is what type classes are for: they introduce ad-hoc polymorphism.
And speaking of "methods": based on this word, I'm guessing those fn functions are coming from some JavaScript library, right? If that's the case, I believe you're doing it wrong. It's bad practice to leak PureScript-land types into JS code. First of all JS code might accidentally corrupt them (e.g. by mutating), and second, PureScript compiler might change internal representations of those types from version to version, which will break your bindings.
A better way is to always specify FFI bindings in terms of primitives (or in terms of types specifically intended for FFI interactions, such as the FnX family), and then have a layer of PureScript functions that transform PureScript-typed parameters to those primitives and pass them to the FFI functions.

Similar record types in a list/array in purescript

Is there any way to do something like
first = {x:0}
second = {x:1,y:1}
both = [first, second]
such that both is inferred as {x::Int | r} or something like that?
I've tried a few things:
[{x:3}] :: Array(forall r. {x::Int|r}) -- nope
test = Nil :: List(forall r. {x::Int|r})
{x:1} : test -- nope
type X r = {x::Int | r}
test = Nil :: List(X) -- nope
test = Nil :: List(X())
{x:1} : test
{x:1, y:1} : test -- nope
Everything I can think of seems to tell me that combining records like this into a collection is not supported. Kind of like, a function can be polymorphic but a list cannot. Is that the correct interpretation? It reminds me a bit of the F# "value restriction" problem, though I thought that was just because of CLR restrictions whereas JS should not have that issue. But maybe it's unrelated.
Is there any way to declare the list/array to support this?
What you're looking for is "existential types", and PureScript just doesn't support those at the syntax level the way Haskell does. But you can roll your own :-)
One way to go is "data abstraction" - i.e. encode the data in terms of operations you'll want to perform on it. For example, let's say you'll want to get the value of x out of them at some point. In that case, make an array of these:
type RecordRep = Unit -> Int
toRecordRep :: forall r. { x :: Int | r } -> RecordRep
toRecordRep {x} _ = x
-- Construct the array using `toRecordRep`
test :: Array RecordRep
test = [ toRecordRep {x:1}, toRecordRep {x:1, y:1} ]
-- Later use the operation
allTheXs :: Array Int
allTheXs = test <#> \r -> r unit
If you have multiple such operations, you can always make a record of them:
type RecordRep =
{ getX :: Unit -> Int
, show :: Unit -> String
, toJavaScript :: Unit -> Foreign.Object
}
toRecordRep r =
{ getX: const r.x
, show: const $ show r.x
, toJavaScript: const $ unsafeCoerce r
}
(note the Unit arguments in every function - they're there for the laziness, assuming each operation could be expensive)
But if you really need the type machinery, you can do what I call "poor man's existential type". If you look closely, existential types are nothing more than "deferred" type checks - deferred to the point where you'll need to see the type. And what's a mechanism to defer something in an ML language? That's right - a function! :-)
newtype RecordRep = RecordRep (forall a. (forall r. {x::Int|r} -> a) -> a)
toRecordRep :: forall r. {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
allTheXs = test <#> \(RecordRep r) -> r _.x
The way this works is that RecordRep wraps a function, which takes another function, which is polymorphic in r - that is, if you're looking at a RecordRep, you must be prepared to give it a function that can work with any r. toRecordRep wraps the record in such a way that its precise type is not visible on the outside, but it will be used to instantiate the generic function, which you will eventually provide. In my example such function is _.x.
Note, however, that herein lies the problem: the row r is literally not known when you get to work with an element of the array, so you can't do anything with it. Like, at all. All you can do is get the x field, because its existence is hardcoded in the signatures, but besides the x - you just don't know. And that's by design: if you want to put anything into the array, you must be prepared to get anything out of it.
Now, if you do want to do something with the values after all, you'll have to explain that by constraining r, for example:
newtype RecordRep = RecordRep (forall a. (forall r. Show {x::Int|r} => {x::Int|r} -> a) -> a)
toRecordRep :: forall r. Show {x::Int|r} => {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
showAll = test <#> \(RecordRep r) -> r show
Passing the show function like this works, because we have constrained the row r in such a way that Show {x::Int|r} must exist, and therefore, applying show to {x::Int|r} must work. Repeat for your own type classes as needed.
And here's the interesting part: since type classes are implemented as dictionaries of functions, the two options described above are actually equivalent - in both cases you end up passing around a dictionary of functions, only in the first case it's explicit, but in the second case the compiler does it for you.
Incidentally, this is how Haskell language support for this works as well.
Folloing #FyodorSoikin answer based on "existential types" and what we can find in purescript-exists we can provide yet another solution.
Finally we will be able to build an Array of records which will be "isomorphic" to:
exists tail. Array { x :: Int | tail }
Let's start with type constructor which can be used to existentially quantify over a row type (type of kind #Type). We are not able to use Exists from purescript-exists here because PureScript has no kind polymorphism and original Exists is parameterized over Type.
newtype Exists f = Exists (forall a. f (a :: #Type))
We can follow and reimplement (<Ctrl-c><Ctrl-v> ;-)) definitions from Data.Exists and build a set of tools to work with such Exists values:
module Main where
import Prelude
import Unsafe.Coerce (unsafeCoerce)
import Data.Newtype (class Newtype, unwrap)
newtype Exists f = Exists (forall a. f (a :: #Type))
mkExists :: forall f a. f a -> Exists f
mkExists r = Exists (unsafeCoerce r :: forall a. f a)
runExists :: forall b f. (forall a. f a -> b) -> Exists f -> b
runExists g (Exists f) = g f
Using them we get the ability to build an Array of Records with "any" tail but we have to wrap any such a record type in a newtype before:
newtype R t = R { x :: Int | t }
derive instance newtypeRec :: Newtype (R t) _
Now we can build an Array using mkExists:
arr :: Array (Exists R)
arr = [ mkExists (R { x: 8, y : "test"}), mkExists (R { x: 9, z: 10}) ]
and process values using runExists:
x :: Array [ Int ]
x = map (runExists (unwrap >>> _.x)) arr

How to implement twice function (function that executes other function twice)? Could not match type Record with type Function Int

Here is the code
module Main where
import Prelude
twice1 f = f . f
transform :: Int -> Int
transform n = n + 1
apply1 x = (twice1 transform) x
I have an error
Could not match type
Record
with type
Function Int
What's wrong? (you can try code here http://try.purescript.org)
PureScript uses the dot . for accessing record fields, as in:
r = { a: 42, b: "what?!" }
fourtyTwo = r.a
The function composition operator in PureScript is <<< (or >>> for left-to-right composition), for example:
twice1 f = f <<< f

Can I condense this expression by using some `map` or `apply`?

I have this code which I'd like to condense
runFn someFn $ toArray a1 $ toArray a2 $ toArray a3 $ toArray a4
I would envision something like
runFn someFn <$> fmap toArray [a1, a2, a3, a4]
In that case runFn someFn would create a partially applied function that awaits its missing parameters and gets then applied one by one on the elements of the array.
I must admit I dont know if the type system will allow for this.
Edit
As it was asked for - here the actual type signatures for this.
However my question is a more general one:
Can I put the parameters of an function into an array if those parameters are of the same type and the partially apply the function array element by array element.
type Numbers = Array Number
foreign import _intersect :: Numbers -> Numbers -> Numbers -> Numbers -> Point2D
data Point2D = Point2D Number Number
toArray :: Point2D -> Numbers
toArray (Point2D x y) = [x, y]
a1 = Point2D 0.5 7.0
a2 = Point2D 3.0 5.1
b1 = Point2D 2.5 9.0
b2 = Point2D 2.1 3.6
intersection :: Numbers -- 2 element Array Number
intersection = _intersect (toArray a1) (toArray a2) (toArray b1) (toArray b2)
If I understand what you're asking here, no you can't. You'd need dependant types to be able to express this, as you'd need some way of ensuring the function arity and array length are equal at the type level.
If we are allowed to change the question slightly, we might be able to achieve what I think you want. The fact that all functions are curried allows us to use type class instance resolution to come up with some tricks that sort of allow us to do things with functions of arbitrary arity. For example:
module Main where
import Prelude
import Data.Foldable (sum)
import Control.Monad.Eff.Console (print)
class Convert a b where
convert :: a -> b
data Point2D = Point2D Number Number
type Numbers = Array Number
instance convertId :: Convert a a where
convert = id
instance convertPoint :: Convert Point2D (Array Number) where
convert (Point2D x y) = [x, y]
instance convertChain :: (Convert b a, Convert r r') => Convert (a -> r) (b -> r') where
convert a2r b = convert (a2r (convert b))
f :: Numbers -> Numbers -> Number
f xs ys = sum xs * sum ys
g :: Point2D -> Point2D -> Number
g = convert f
f' :: Numbers -> Numbers -> Numbers -> Numbers -> Number
f' a b c d = f a b + f c d
g' :: Point2D -> Point2D -> Point2D -> Point2D -> Number
g' = convert f'
main =
print $ g'
(Point2D 1.0 2.0)
(Point2D 3.0 4.0)
(Point2D 5.0 6.0)
(Point2D 7.0 8.0)
These techniques have some nice applications. QuickCheck, for example, uses a similar technique to allow you to call quickCheck on functions of any arity, as long as all the arguments have Arbitrary instances. In this specific case, though, I think I would stick to the simpler, more boilerplate-y solution: unrestrained use of type classes can become quite unwieldy, and can produce very confusing error messages.

Optional argument in a method with ocaml

I encounter a problem with a optional argument in a method class.
let me explain. I have a pathfinding class graph (in the Wally module) and one his method shorthestPath. It use a optional argument. The fact is when I call (with or not the optional argument) this method OCaml return a conflict of type :
Error: This expression has type Wally.graph
but an expression was expected of type
< getCoor : string -> int * int;
getNearestNode : int * int -> string;
shorthestPath : src:string -> string -> string list; .. >
Types for method shorthestPath are incompatible
whereas shorthestPath type is :
method shorthestPath : ?src:string -> string -> string list
I same tried to use the option format for a optional argument :
method shorthestPath ?src dst =
let source = match src with
| None -> currentNode
| Some node -> node
in
...
Only in the case where I remove the optionnal argument, OCaml stop to insult me.
Thank you in advance for your help :)
It is not very clear what your situation is but I guess the following:
let f o = o#m 1 + 2
let o = object method m ?l x = match l with Some y -> x + y | None -> x
let () = print_int (f o) (* type error. Types for method x are incompatible. *)
The use site (here the definition of f), the type of object is inferred from its context. Here, o : < x : int -> int; .. >. The method x's type is fixed here.
The object o defined later is independent from the argument of f and has the type < m : ?l:int -> int -> int; .. >. And unfortunately this type is incompatible with the other.
A workaround is to give more typing context to the use site about the optional argument:
let f o = o#m ?l:None 1 + 2 (* Explicitly telling there is l *)
let o = object method m ?l x = match l with Some y -> x + y | None -> x end
Or give the type of o:
class c = object
method m ?l x = ...
...
end
let f (o : #c) = o#m 1 + 2 (* Not (o : c) but (o : #c) to get the function more polymoprhic *)
let o = new c
let () = print_int (f o)
I think this is easier since there is usually a class declaration beforehand.
This kind of glitch between higher order use of functions with optional arguments happens also outside of objects. OCaml tries to resolve it nicely but it is not always possible. In this case:
let f g = g 1 + 2
let g ?l x = match l with Some y -> x + y | None -> x
let () = print_int (f g)
is nicely typed. Nice!
The key rule: if OCaml cannot infer about omitted optional arguments, try giving some type context about them explicitly.