New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keep track of templates for callables #4589
Comments
I found these snippets: https://psalm.dev/r/6e44e1eccf<?php
/**
* @template T
* @template B
* @psalm-param T $e
* @psalm-return callable(callable(T): B): B
*/
function foo($e): callable
{
return function ($fab) use ($e) {
return $fab($e);
};
}
foo('foo')(fn (string $a) => strlen($a));
https://psalm.dev/r/4efcc7e309<?php
/**
* @template B
* @psalm-return callable(B): B
*/
function foo(): callable
{
return function ($fab) {
return $fab;
};
}
foo()('bar');
|
Looking at this example: I think it should be possible.
@weirdan what do you think? |
I found these snippets: https://psalm.dev/r/b6c1411ec4<?php
/**
* @template T
* @template B
* @psalm-param T $e
* @psalm-return callable(callable(T): B): B
*/
function foo($e): callable
{
return function ($fab) use ($e) {
return $fab($e);
};
}
foo('foo')(fn (string $a) => strlen($a));
|
That would mean |
I found these snippets: https://psalm.dev/r/b618884527<?php
/**
* @template T
*/
class myInvokable {
/** @var T */
private $e;
/** @param T $e */
public function __construct($e) { $this->e = $e; }
/**
* @template B
* @param callable(T): B $p
* @return B
*/
public function __invoke($p) {
return $p($this->e);
}
}
/**
* @template T
* @psalm-param T $e
* @return myInvokable<T>
*/
function foo($e): callable
{
return new myInvokable($e);
}
$_z = foo('foo')(fn (string $a) => strlen($a));
/** @psalm-trace $_z */;
// var_dump($_z);
|
In your example you are wrapping almost the same logic in a invokable class, but with the same behaviour. But it's impossible with already existing librararies, and excessive to creare a class for a simple lambda function, and I think it's something that will be use more in the next years starting from PHP 7.4 with arrow functions. Now, a function like that will use |
Indeed. The point of this exercise was to see how it maps to concepts already used in Psalm and to check if it's sound. I'm not suggesting you to actually rewrite anything. |
Oh, maybe as the first thing, should psalm support templates in closures? Or I'm doing something wrong here? That's why my experimental plugin wasn't working :) |
I found these snippets: https://psalm.dev/r/79c407cbf4<?php
$f1 =
/**
* @template T
* @param T $e
* @return T
*/
function ($e)
{
return $e;
};
$valueF1 = $f1('a');
|
Probably related to #4550 |
Consider the following two examples.
I think it should be possible to keep track of template references and infer the right type of the return type.
https://psalm.dev/r/6e44e1eccf
https://psalm.dev/r/4efcc7e309
For example, in the above code, as the interal psalm code does, function
foo()
should return acallable(B:fn-foo as mixed): B:fn-foo as mixed
, so that calling this callable we know that the return type is the first argument.Same in the following code:
Here, nested callables should keep track of the template.
Without this improvement, it's almost impossible to work with nested callables, specially developing or documenting a functional programming library.
I think it should be possible, right?
The text was updated successfully, but these errors were encountered: