In trying to understand how to implement forall in JS or Ruby, I would be interested to know how it's actually implemented in Coq. Maybe that will help shed some light. I don't seem to find the definition by searching around on Google. Mainly just looking for a link in the source code somewhere.
Coq's forall is a dependent product type and cannot be directly encoded in a dynamically typed languages like Javascript because they simply lack the concept of static type.
It serves the purpose of giving a static type to some nonsensical from the point of view of some languages, functions. Consider we have an infinite collection of types T1, T2...
Then this function cannot be assigned a (nontrivial) type by conventional methods:
function foo(n) {
return eval("new T" + n + "()");
}
However, we can give it dependent (forall) type, using a helper function
function H(n) {
return eval("T" + n);
}
The type of foo then will be forall n:Number, H(n) (given Number, returns an object of type H(n), ie Tn).
Unfortunately, there is no way for us to convey this information to the JS interpreter to statically enforce this contract. However, we can check it at runtime!
Lets start by making a small type checking framework.
function type_number(x) {
if (typeof x == "number") return x;
throw new Error("not a number");
}
function type_function(x) {
if (typeof x == "function") return x;
throw new Error("not a function");
}
function type_instance(clss) {
return function (x) {
if (x instanceof clss) return x;
throw new Error("not an instance of " + clss);
};
}
Now we can implement a non-dependent function type
function type_arrow(arg, ret) {
return function(f) {
f = type_function(f);
return function(x) {
return ret(f(arg(x)));
};
};
}
Here arg must be a type checker for the argument, and ret must be a type checker for the return value. For example:
// declare a function from numbers to numbers
var fn1 = type_arrow(type_number, type_number)((x) => x * x);
fn1(10); // works
fn1("asdsa"); // fails
// bad declaration, but, unfortunately, JS cannot possibly catch it at "compilation" time
var fn2 = type_arrow(type_number, type_number)((x) => "Hello!");
fn2(10); // fails, return value is not a number
Now to the fun part:
function type_forall(arg, ret) {
return function(f) {
f = type_function(f);
return function(x) {
var y = f(arg(x));
return ret(x)(y);
};
};
}
Notice how ret is now a curried function of two arguments. Given my first example, we can now give a type to foo:
function T1(){}
function T2(){}
function T3(){}
function T4(){}
function T5(){}
// ...etc
function foo(n) {
return eval("new T" + n + "()");
}
function H(n) {
return eval("T" + n);
}
function type_H(n) {
return type_instance(H(n));
}
var typed_foo = type_forall(type_number, type_H)(foo);
typed_foo(2); // successfully invokes and returns a T2 instance
Note that we cannot give a non-trivial type to foo with type_arrow - we need n to properly typecheck the return value.
But this is nowhere near the power Coq gives us, simply because it does not catch any errors at compile time. If you really want these guarantees, you must materialize language constructs as first class objects and perform your own type checking. One article I could recommend is http://augustss.blogspot.com/2007/10/simpler-easier-in-recent-paper-simply.html
Related
Say that I have an uncurried function like:
let echo(. a) = a;
I can call this funcition fine with most literals like:
echo(. 1)
echo(. "Hello")
but when I am trying to call it with void, I get an error:
echo(. ()) //This function has arity1 but was expected arity0
As a workaround, I can do this:
let myArg = ()
echo(. myArg)
Is there a way to avoid this?
I like this version as well:
echo(. ignore())
that way I don't need the dummy value workaround
Edit: This version is also now part of the docs: https://rescript-lang.org/docs/manual/latest/function#uncurried-function
It looks like you are trying to call an un curried function that takes one parameter with no arguments because that is what () means right. The only reason it works with
echo(. myArg) is in this case the compiler is declaring an un initialized variable called myArg and passing that to echo.
EDIT: you can look at what I mean at re-script playground here
let echo = (. a) => a;
let k =() => echo(. "String")
let myArg = ()
let s =() => echo (. myArg)
generates
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
function echo(a) {
return a;
}
function k(param) {
return echo("String");
}
function s(param) {
return echo(undefined);
}
var myArg;
exports.echo = echo;
exports.k = k;
exports.myArg = myArg;
exports.s = s;
/* No side effect */
Apparently, this is a known issue in rescript. See: https://github.com/rescript-lang/rescript-compiler/issues/3429
Im getting error in if(Liste.length>1), i want to make a function to return true if list is ordered low to high. Having some problems with Boolean returning.
object Soru5 extends App {
//A function returns true if list is ordered low to high
def kucukten_buyuge_siralimi(Liste:List[Int]):Boolean=
{
var i=0
var ListeIslem=Liste
if(Liste.length==0) false
if(Liste.length==1) true
if(Liste.length>1) //***********ERROR************ found->Unit,Boolean required
{
while(i<Liste.length-1)
{
var onceki=ListeIslem.head //onceki is first element of list
var sonraki=(ListeIslem.tail).head //sonraki is second element of list
if(onceki>sonraki)
{
return false
}
else
{
ListeIslem=ListeIslem.tail
i=i+1
}
}
return true
}
}
val listem=List(3,2,1)
println(kucukten_buyuge_siralimi(listem))
}
The return value of a method is the value of the last expression evaluated inside the method body. In your case, the last expression inside the method body is:
if(Liste.length>1) {
// …
}
So … what is the value of this expression if the length is less than 2? There is no value! Actually, in Scala, there is (almost) always a value, so the value of this is () which is of type Unit and denotes the absence of a value.
In other words, if the length is less than 2, your method will return () of type Unit, but it promises to return something of type Boolean. You need to add an else clause to your if expression that also returns a Boolean.
This is the immediate cause of the error.
Note that there are also some other problems with your code besides that. For example, those two lines don't actually do anything:
if(Liste.length==0) false
if(Liste.length==1) true
They simply evaluate to a value, but you don't actually do anything with that value, you don't store it in a variable, you don't return it, you don't pass it as an argument … it just vanishes.
Note also that your code violates the Community Coding Style.
And last but not least, your code just doesn't read like Scala. It reads more like a mix of Fortran and Basic. Scala style would be more like this:
def isMonotonicallyIncreasing(l: List[Int]) =
if (l.size < 2) true else l.sliding(2).forall { case (a :: b :: Nil) ⇒ a <= b }
i.e. a list is monotonically increasing if for all subsequent pairs of elements, the left element is not greater than the right element.
Because there's no else between ifs, they are separate. You effectively have
if (Liste.length==0) false else ();
if (Liste.length==1) true else ();
if (Liste.length>1) ... else ();
else () is what the compiler inserts for every if without else.
The compiler has no idea that Liste.length will be the same each time or that it will never be negative. It would be better to write
Liste.length match {
case 0 => false
case 1 => true
case n => ...
You can use n in the last branch instead of calculating length yet again.
This can be improved further, of course, but I think it's out of scope for this answer.
I'd like to assume a given type implements some trait (e.g. Default) with a method (e.g. default()). I want to call that method and store its value into a local variable. Here is a general idea of it:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = $x::default();
};
}
fn main() {
// get_default!(i32 = z);
// println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
Playground link.
When I try that I get an error:
error: expected expression, found `i32`
--> <anon>:3:22
|>
3 |> let $alias = $x::default();
|> ^^
I understand it's because it expects an expression, but I want to limit input to types only. Is there a way to turn $x from ty to expr, or a way to call a method on a type (even if it's potentially missing).
You were almost there. You can hint the expected default type to the compiler and then just use the universal function call syntax:
macro_rules! get_default {
( $x:ty = $alias:ident ) => {
let $alias = <$x as Default>::default();
};
}
fn main() {
get_default!(i32 = z);
println!("get_default! {:?} ", z);
println!("i32 default {:?} ", i32::default());
}
(Playground link)
The key bit is this:
let $alias = <$x as Default>::default();
This casts $x to the Default trait and then invokes the default() method, as you needed.
You can also use a shorthand when you don't need to disambiguate between traits:
let $alias = <$x>::default();
(Playground link)
More General Usage of UFCS
Using UFCS as shown above, you can disambiguate between traits that implement the same methods. This is the 'angle-bracket form' which is useful if the default() method is implemented in two traits.
In this specific scenario, you can also use UFCS more specifically, like so:
let $alias: $x = Default::default();
That alone provides enough information for Rust to infer the correct impl.
(Playground link)
struct Type
{
auto opBinary(string op)(Type other) const {
return Type(); // #1 return type is Type
return typeof(this)(); // #2 return type is const(Type)
}
}
unittest
{
Type t1, t2;
auto t3 = t1 + t2;
}
In t1.opBinary!("+")(t2), t1 becomes a const, while t2 stays non-const. Should opBinary's return type be Type or const(Type), and why?
const(T) is a supertype, so maybe it should return a const, but I've hardly seen this in practice. Things also become rather complicated when dealing with a hierarchy of types and functions that use those types or are used by those types.
Since the return value here is a new object, I'd say make it non-const. Being new, it can be modified safely, so no reason to unnecessarily restrict it with const.
If you were returning a part of the existing object, you'll want to use inout instead of const. inout means the constness of the object will also go to the return value.
inout(Type) opBinary(string op)(Type other) inout {
return whatever;
}
Now if you use a const(Type) object, the return will be const as well, and if it is called on a mutable object, the return is also mutable.
Should return type be T or const(T)? Any will do.
Which one is better? Depends on your intended behavior.
const qualifier on opBinary only means that hidden "this" argument is const. Nothing more, nothing else. It does not imply anything about the return type. It all boils down to pretty simple choice:
struct Type
{
int a;
auto opBinary(string op)(Type other) const
if (op == "+")
{
return Type(this.a + other.a);
}
}
void main()
{
Type first, second;
(first + second).a = 42; // Do you want to allow this?
// Yes -> return non-const
// No -> return const
}
If you want to preserve qualifiers of arguments, use either inout (see Adams answer) or manual check for qualifiers for more complicated choices.
With either choice remember automatic type deduction:
auto third = first + second;
third.a = 42; // Error if returns const
Type fourth = first + second;
fourth.a = 42; // Fine in both cases, struct was copied
In the end it is about you intention as a type designer how class/struct should behave.
i got an error that said "error: conflicting types for '____'. What does that mean?
Quickfix:
Make sure that your functions are declared once and only once before they are called. For example, change:
main(){ myfun(3.4); }
double myfun(double x){ return x; }
To:
double myfun(double x){ return x; }
main(){ myfun(3.4); }
Or add a separate function declaration:
double myfun(double x);
main(){ myfun(3.4); }
double myfun(double x){ return x; }
Possible causes for the error
Function was called before being declared
Function defined overrides a function declared in an included header.
Function was defined twice in the same file
Declaration and definition don't match
Declaration conflict in the included headers
What's really going on
error: conflicting types for ‘foo’ means that a function was defined more than once with different type signatures.
A file that includes two functions with the same name but different return types would throw this error, for example:
int foo(){return 1;}
double foo(){return 1.0;}
Indeed, when compiled with GCC we get the following errors:
foo.c:5:8: error: conflicting types for ‘foo’
double foo(){return 1.0;}
^
foo.c:4:5: note: previous definition of ‘foo’ was here
int foo(){return 1;}
^
Now, if instead we had a file with two function definitions with the same name
double foo(){return 1;}
double foo(){return 1.0;}
We would get a 'redefinition' error instead:
foo.c:5:8: error: redefinition of ‘foo’
double foo(){return 1.0;}
^
foo.c:4:8: note: previous definition of ‘foo’ was here
double foo(){return 1;}
^
Implicit function declaration
So why does the following code throw error: conflicting types for ‘foo’?
main(){ foo(); }
double foo(){ return 1.0; }
The reason is implicit function declaration.
When the compiler first encounters foo() in the main function, it will assume a type signature for the function foo of int foo(). By default, implicit functions are assumed to return integers, and the input argument types are derived from what you're passing into the function (in this case, nothing).
Obviously, the compiler is wrong to make this assumption, but the specs for the C (and thus Objective-C) language are old, cranky, and not very clever. Maybe implicitly declaring functions saved some development time by reducing compiler complexity back in the day, but now we're stuck with a terrible feature that should have never made it into the language. In fact, implicit declarations were made illegal in C99.
That said, once you know what's going on, it should be easy to dig out the root cause of your problem.
it's probably because your function "_" already exists in your library. It happened to me with this function:
I was using stdio.h
int getline (char s[ ] , int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
When I changed "getline" to "getlinexxx" and gcc compiled it:
int getlinexxx (char s[], int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
And the problem was gone
What datatype is '___'?
My guess is that you're trying to initialize a variable of a type that can't accept the initial value. Like saying int i = "hello";
If you're trying to assign it from a call that returns an NSMutableDictionary, that's probably your trouble. Posting the line of code would definitely help diagnose warnings and errors in it.