How to correctly unwrap `data` inside `data`? - purescript

I’m trying to access nested data (Foo.y inside Bar in the example below), but the straightforward approaches for unwrapping Foo inside Bar that come to mind do not work. But how to unwrap it correctly?
Here my data:
module Foo where
import Prelude
data Foo = Foo { y :: Int }
data Bar = Bar { x :: Int
, foo :: Foo }
The following (of course) does not compile, error is Could not match type { y :: Int } with type Foo — just like Bar, Foo needs unwrapping first:
fn1 :: Bar -> Int
fn1 (Bar { x, foo }) = x + foo.y
So I put up my hopes for the following, but alas, compiler says “no” (parentheses around Foo constructor don’t help):
fn2 :: Bar -> Int
fn2 (Bar { x, Foo { y } }) = x + y
fn3 :: Bar -> Int
fn3 (Bar { x, Foo f }) = x + f.y
The following works, using a helper function to do the unwrapping, but there has got to be a better way:
getY (Foo foo) = foo -- helper function
fn4 :: Bar -> Int
fn4 (Bar { x, foo }) = let foo2 = getY foo in
x + foo2.y
So, how do I do nested “unwrap”?
[EDIT]
After an hour or two of trying things out, I came up with this, which works:
fn5 :: Bar -> Int
fn5 (Bar { x, foo = (Foo f) }) = x + f.y
Is this the idiomatic way to do it? Why don’t fn2 and fn3 work?

Functions fn2 and fn3 do not work because the compiler does not know which record field you are referring to (foo). You have to reference record fields by name.
Function fn4 is a perfectly fine solution (although your naming is pretty confusing, getY actually returns the wrapped record inside the Foo constructor, not the y value).
As far as I can tell, fn5 is the shortest possible solution. I would personally prefer a helper function (like in your fourth example):
getY :: Foo -> Int
getY (Foo rec) = rec.y
fn6 :: Bar -> Int
fn6 (Bar { x, foo }) = x + getY foo

Related

Using class field in lambda as parameter Scala

I am trying to create a constructor in which one of the methods could be passed. See my code:
class Foo(fooMethod: () => Unit, var x: Int, var y: Int) {
def foo() = fooMethod()
}
class Bar(x: Int) extends Foo(() => {
var test1 = x
var test2 = y
println(x + ", " + y)
}, x, 50)
class FieldDemo {
def main(args: Array[String]): Unit = {
val bar = new Bar(40)
bar.foo()
}
}
The in this example val test1 = x does work, because it is a parameter of the Bar constructor, but val test2 = y does not work, even though Bar extends Foo and Foo has a field named y.
So my question is: why do you not have access to the y of the Foo class variable from within the function in Bar
EDIT:
When reading the answer, also look at the first comment by Matheusz Kubuszok and http://ideone.com/9yMpvw vs http://ideone.com/0fDxXe. The second link is the reason why the code in the first link should also fail. I imagine that edge case detection like this would make the compiler way more complex so I now indeed understand why they chose not to allow it.
Basically your code is equivalent to something like:
val barFun(x: Int) = () => {
var test1 = x
var test2 = y
println(x + ", " + y)
}
class Bar(x: Int) extends Foo(barFun(x), x, 50)
When you are creating your lambda, it only sees arguments passed into constructor - it is created within the scope of a constructor, so it has access to variables passed into it as a closure. It does not have access to Foo class as it is not its enclosing class. You can check it if you do something like:
class Bar(z: Int) extends Foo(() => {
var test1 = x
var test2 = y
println(x + ", " + y)
}, z, 50)
You'll see that lambda will have no access to neither x nor y. Other test I tried in ammonite shows this:
class Bar(z: Int) extends Foo(() => {
var test1 = Foo.this.x
var test2 = Bar.this.y
}, z, 50)
cmd1.sc:2: Foo is not an enclosing class
var test1 = Foo.this.x
^
cmd1.sc:3: Bar is not an enclosing class
var test2 = Bar.this.y
^
Compilation Failed
As a matter of the fact, this makes sens. At the moment you are creating the lambda, class is not yet initialized. If whatever you do during class initialization had access to all those uninitialized vars, things could turn nasty.

Partial application with named parameters [duplicate]

This question already has answers here:
Underscore in Named Arguments
(2 answers)
Closed 6 years ago.
If I use partial application on a method (the apply() method of my case class here), it works:
case class Foo(a : Int, b : Int)
val pf : Int => Foo = Foo(_ ,2)
However, it doesn't appear to be possible to use this in combination with named parameters, e.g. :
case class Foo(a : Int, b : Int)
val pf : Int => Foo = Foo(a = _ ,b = 2)
it results in :
Error:(7, 33) not found: value a
lazy val pf : Int => Foo = Foo(a = _ ,b = 2)
^
Is there any way around this? I need this because I have case classes with a large number of default parameters, that I don't want to have to specify most of the time.
(Scala 2.11)
Syntactically, underscore is bound at the enclosing expression, and assignment is an expression.
So your example expands to Foo(x => a = x, b = 2).
That's done by the parser, before anyone asks if you intended named args.
Workaround: val pf : Int => Foo = i => Foo(a = i ,b = 2)
Unfortunately. you cannot use placeholder syntax to expand function this way.
This is because of compiler behavior, it tries to expand undersore to the closest position and then you will have an
val pf : Int => Foo = Foo((x => a = x) ,b = 2)
instead of
val pf : Int => Foo = x => Foo(a = x ,b = 2)
In first example "a" is surely not defined in context of anonymous function and will result an error.
I suggest you to use second example to work with named parameters. Additionally, it's much cleaner in code exceptionally if you accept multiple parameters.

How to use type constrains with Exists

data Foo a = Foo a
I can create an array of Exists https://github.com/purescript/purescript-exists
[(mkExists (Foo 0)), (mkExists (Foo "x"))]
How can I use type classes? I want to get ["0", "x"]
getStrings :: Array (Exists Foo) -> Array String
getStrings list = map (runExists get) list
where
get :: forall a. Show a => Foo a -> String
get (Foo a) = show a
No type class instance was found for
Prelude.Show _0
The instance head contains unknown type variables. Consider adding a
type annotation.
One option is to bundle up the show function in your definition of Foo, something like this:
import Prelude
import Data.Exists
data Foo a = Foo a (a -> String)
type FooE = Exists Foo
mkFooE :: forall a. (Show a) => a -> FooE
mkFooE a = mkExists (Foo a show)
getStrings :: Array FooE -> Array String
getStrings = map (runExists get)
where
get :: forall a. Foo a -> String
get (Foo a toString) = toString a
--
items :: Array FooE
items = [mkFooE 0, mkFooE 0.5, mkFooE "test"]
items' :: Array String
items' = getStrings items

How can I create an array with polymorphic data?

I am trying to do this
data Foo a = Foo a
data FooWrapper = FooWrapper (forall a. Foo a)
foo = [FooWrapper (Foo 0), FooWrapper (Foo "")]
But there is an error
Could not match type
Int
with type
a0
Existential types don't quite work the same in PureScript as they do in Haskell, so usually we use the purescript-exists library for this kind of thing.
The equivalent using Exists would be:
import Data.Exists (Exists(), mkExists)
data Foo a = Foo a
data FooWrapper = FooWrapper (Exists Foo)
foo = [FooWrapper (mkExists (Foo 0)), FooWrapper (mkExists (Foo ""))]
I suppose in this case you probably don't need FooWrapper at all and could just have an array of Exists Foo.
I wanted to know how Phil Freeman's suggested approach works, so I gave it a try. This is a working example of storing a type class instance with its value by using a rank-n type.
module Example where
import Prelude (class Show, Unit, discard, pure, show, unit, ($))
import Effect (Effect)
import Effect.Console (log)
newtype Showable = Showable (forall r. (forall a. Show a => a -> r) -> r)
instance showShowable :: Show Showable where
show (Showable f) = f show
mkShowable :: forall s . Show s => s -> Showable
mkShowable s = Showable (\f -> f s)
showables :: Array Showable
showables = [mkShowable 1, mkShowable "a string", mkShowable { foo : "bar" } ]
main :: Effect Unit
main = do
log $ show showables
pure unit
The newtype is not really necessary for storing, but i wanted to create an instance of Show for the type itself .

How to get value out of anonymous function in scala?

I am trying to learn scala and understand difference between functions and methods.
Here is very simple code I wrote -
scala> class C ( acc:Int) {
| val minc = ( acc + 1 )
| val func = { () => acc += 3 }
| }
scala> val c1 = new C(3)
c1: C = C#55e610e3
scala> c1.minc
res2: Int = 4
scala> c1.func
res3: () => Int = <function0>
I understand that result of calling function func on instantiated object c1 is stored as another expression res3.
However I want to get value out of of anonymous function () = acc +3 that is inside class C.
If I try to pass argument to res3 expression scala throws an error
scala> res3(4)
<console>:11: error: too many arguments for method apply: ()Int in trait Function0
res3(4)
^
How to get value out of it ?
PS - I have just started with scala and don't know if this is at all possible or not ?
This is your definition of func:
val func = { () => acc += 3 }
Let's take a look in the REPL at what is the type of func.
scala> val c1 = new C(3)
val c1 = new C(3)
c1: C = C#58db88e9
scala> c1.func
c1.func
res29: () => Unit = <function0>
In plain English, this means "func refers to a function that accepts no arguments and doesn't return a value." Unit means the method doesn't return anything. If you're coming from Java, then it's analogous to void as the return type. function0 means it accepts 0 arguments.
Next, let's take a look at the failing call in your example.
scala> c1.func(4)
c1.func(4)
<console>:10: error: too many arguments for method apply: ()Unit in trait Function0
c1.func(4)
^
Now that we know the method signature of func, this error message should make more sense. We know that func refers to a function that accepts no arguments, yet in this call, you have attempted to call it with a single integer argument. Since the method call has too many arguments, Scala correctly reports this as an error.
I am not entirely sure what you were trying to do by passing 4 as an argument. My best guess is that you are trying to apply the function to calculate its result by adding 3 to acc and then returning it to the caller. If I'm right, then we can redefine C as this:
class C(var acc:Int) {
val minc = ( acc + 1 )
val func = () => {
acc += 3
acc
}
scala> val c1 = new C(3)
val c1 = new C(3)
c1: C = C#58db88e9
scala> c1.func()
c1.func()
res44: Int = 6
When we call c1.func(), no arguments are passed, so it correctly matches the defined method signature.
Another possibility is that you were trying to parameterize the increment amount and pass 4 to it in the call. If so, then you can do this:
class C(var acc:Int) {
val minc = ( acc + 1 )
val func = (delta: Int) => {
acc += delta
acc
}
}
scala> c1.func(4)
c1.func(4)
res45: Int = 7
In this case, we have declared that the anonymous function accepts 1 argument of type Int, so when we pass 4 in the method call, it correctly matches the method signature.
You're not declaring an anonymous function in the way you think. This line:
val func = { () => acc += 3 }
That actually declares 2 anonymous functions. The brackets are the first anonymous function (that takes no arguments), and the () => acc += 3 is the second function. Scala allows you to declare a 0-arity anonymous function by just using brackets. If you drop those, you'll have what you want:
val func = () => acc += 3
As a bit of a side note, you can see this in the type signature. Your current signature for func is:
() => Int = <function0>
That's a function that takes 0 arguments and returns an integer. That's not what you want. When you change it to what I gave you, you'll get this:
Int => Int = <function1>
Now func takes a single argument, and Integer, and returns another Integer, which is what you wanted.