In Scala, I can make a caseclass, case class Foo(x:Int), and then put it in a list like so:
List(Foo(42))
Now, nothing strange here. The following is strange to me. The operator :: is a function on a list, right? With any function with one argument in Scala, I can call it with infix notation.
An example is 1 + 2 is a function (+) on the object Int. The class Foo I just defined does not have the :: operator, so how is the following possible?
Foo(40) :: List(Foo(2))
In Scala 2.8 RC1, I get the following output from the interactive prompt:
scala> case class Foo(x:Int)
defined class Foo
scala> Foo(40) :: List(Foo(2))
res2: List[Foo] = List(Foo(40), Foo(2))
I can go on and use it, but what is the explanation?
From the Spec:
6.12.3 InfixOperations An infix operator can be an arbitrary
identifier. Infix operators have
precedence and associativity defined
as follows.
...
The associativity of an operator is
determined by the operator’s last
character. Operators ending in a colon
‘:’ are right-associative. All other
operators are left- associative.
You can always see how these rules are applied in Scala by printing the program after it has been through the 'typer' phase of the compiler:
scala -Xprint:typer -e "1 :: Nil"
val r: List[Int] = {
<synthetic> val x$1: Int = 1;
immutable.this.Nil.::[Int](x$1)
};
It ends with a :. And that is the sign, that this function is defined in the class to the right (in List class here).
So, it's List(Foo(2)).::(Foo(40)), not Foo(40).::(List(Foo(2))) in your example.
One aspect missing in the answers given is that to support :: in pattern matching expressions:
List(1,2) match {
case x :: xs => println(x + " " + xs)
case _ => println("")
}
A class :: is defined :
final case class ::[B](private var hd: B, private[scala] var tl: List[B])
so case ::(x,xs) would produce the same result. The expression case x :: xs works because the default extractor :: is defined for the case class and it can be used infix.
The class Foo I just defined does not
have the :: operator, so how is the
following possible:
Foo(40) :: List(Foo(2))
If the method name ends with a colon (:) the method is invoked on the right operand, which is the case here. If the method name doesn't end with colon, the method is invoked on the left operand. For example, a + b, + is invoked on a.
So, in your example, :: is a method on its right operand, which is a List.
Related
I'm trying to create a custom operator that is a synonym for the dot (member access) operator, such that a>>=b results in a.b.
My first attempt does not compile
operator >>= left 19 = (left, right) => {
return #`${left}.${right}]`;
};
If i change . by && in the return statement, then it does compile.
Since the previous approach did not work out, i tried using computed member access:
operator >>= left 19 = (left, right) => {
let r = right.name.token.value; // string representation of an identifier
let dummy = #`dummy`.get(0);
return #`${left} [${fromStringLiteral(dummy, r)}]`;
};
This approach compiles for simple expressions like a>>=b, but not for a>>=b.then(res => ...), because right is now a call expression: b.then(...), which i don't understand since i chose a precedence of 19 for my custom operator, which is also the precedence of [] hence conceptually this means that my expression should be equivalent to (a>>b).then(res => ...) or am i wrong?
I am very new to Ocaml and ML in general and I have been having a very fundamental issue. I am using a pattern match and within one match I would like to print two or more concatenated statements. Eg.
chan^"("^var^")"^op2^(poc p); chan^"("^var^")"^op^(poc p)
let processoperatorchange2 t2s2 proc2 op op2=
let rec poc2 p = match p with
| Zero -> "0"
| Pproc (x) -> String.lowercase x
| In(chan, var, _, p, _) -> chan^"("^var^")"^op^(poc2 p); chan^"("^var^")"^op2^(poc2 p)
in poc2 proc2
But then each time I run this, the only statement printed is the last one after the semi colon. Can I get some help with this?
Your function does not print a statement but builds a string, thus it returns a value, and doesn't perform any side-effects. The semicolon operator, when interspersed between two expressions, doesn't combine the value produced from these expressions, thus if you have "hello"; "world" the result is "world". That is what happens in your case when you do
chan^"("^var^")"^op^(poc2 p); chan^"("^var^")"^op2^(poc2 p)
Everything on the lift is just thrown away.
A quick fix would be to concatenate them, e.g.,
chan^"("^var^")"^op^(poc2 p) ^ ";\n" ^ chan^"("^var^")"^op2^(poc2 p)
But in general, an idiomatic way to print AST is to use the Format module, and implement a recursive pp function, that has type Format.formatter -> 'a -> unit. Note the return type, the function doesn't build a string (that is usually an operation of quadratic complexity), but rather prints it into generic output stream.
In OCaml, is there a way to refer to the cons operator by itself?
For example, I can use (+) and ( * ) as int -> int -> int functions, but I cannot use (::) as a 'a -> 'a list -> 'a list function, as the following example show:
# (+) 3 5;;
- : int = 8
# ( * ) 4 6;;
- : int = 24
# (::) 1 [2;3;4];;
Error: Syntax error: operator expected.
Is there a way to produce a result like (::) other than with fun x y -> x::y? And does anyone know why (::) wasn't implemented in OCaml?
Adding to the answer of #seanmcl,
Actually OCaml supports a prefix form of (::):
# (::)(1, []);;
- : int list = [1]
This is in the uncurried form, corresponding with the fact that all the OCaml variant constructors are not curried and cannot be partially applied. This is handled by a special parsing rule just for (::), which is why you got a rather strange error message Error: Syntax error: operator expected..
Update:
Upcoming OCaml 4.02 removes this parsing rule, therefore this is no longer available.
No. Cons (::) is a constructor, constructors can not be infix operators. The allowed infix symbols are here:
http://caml.inria.fr/pub/docs/manual-caml-light/node4.9.html
Some workarounds are (as you mention) the verbose
(fun x l -> x :: l)
and defining your own nontraditional infix cons
let (+:) x l = x :: l
As of Ocaml 4.03, you can now use cons (in the List module). That is, cons x xs is the same as x :: xs.
It's also possible to just define your own cons function:
let cons = fun a list -> a :: list
I'm supposed to split a string and return the substring that occurs before a passed character, but we're just starting Haskell, and it is like Chinese to me. I've been messing with it, but no luck.
Here's what I have so far:
--spanString returns substring of string s before char c
spanString (c, [s])::(c, [s]) -> []
spanString (c, a:b) =
let (x, y) = spanString (c, b)
in
if a < c then (a:x,y)
else (x, a:y)
What am I messing up?
First of all, your type signature is completely messed up. It must either be absent or be of the form spanString :: <some type>. Even if we ignore the (c, [s]) standing before the double colon, the rest is still something strange. One can read it as "a function taking values of type (c, [s]) to values of type [] for any c and s" (c and s are type variables). First, there is no type [] in Haskell. There is not going be a list type without its element type. Next, we can't work with any c and s. We must be able to compare them, right?
Actually, let's avoid using polymorphism for now and specify exactly which types we want. We want a character and a list of characters, packed up into a tuple for some reason: (Char, [Char]). Note that Char starts with a capital letter, which means it's not a type variable, but rather a concrete type. What about our result type? If you trust the problem description, you need to return a list of characters ([Char]), but if you look at the code, it obviously returns tuples of lists (([Char], [Char])). Okay, maybe the second list is useful, let's leave it for now:
spanString :: (Char, [Char]) -> ([Char], [Char])`
Now your code compiles.
However, when run, it crashes with exception: Non-exhaustive patterns in function spanString. This is because you don't handle the case when the passed list is empty. If you do that, by adding an equation like
spanString (_, []) = ([], [])
, your function runs well, but now let's look at what it does. It turns out you have a function for list partitioning: it returns all characters of the given string less than c as the first element of the tuple and all other characters as the second element. Seems like a bug to me (you've implemented a completely different function!).
Err, quite a lot.
First, your type declaration is wrong. Haskell uses upper case names for types, and it doesn't pass parameters in brackets like most languages do. We write
y = sin x
instead of
y = sin (x)
You probably want something like
spanString :: Char -> String -> String
Your definition of spanString is syntactically right, but still wrong. Think about it this way: if first character doesn't match then you want to spanString the rest of the string and then return the result with the first character prepended. If the first character does match then you want to return "".
Your type definition is wrong .
spanString :: Char-> String-> String
spanString _ [] = []
spanString c (x:xs) | c==x = []
| otherwise = x:spanString c xs
Just for information, utility functions like this can almost always be found in Prelude, or one of the standard libraries. In this case, takeWhile will help:
spanString :: (Char, String) -> String
spanString (c, s) = takeWhile (/= c) s
(i.e., keep taking characters while they don't equal c).
Passing arguments in a tuple is slightly odd, but if that's what's required then so be it.
I have this bit of code:
fun foldr2(f, x::xs) =
if xs = [] then
x
else
f(x, foldr2(f, xs))
With the type signature
(''a * ''a -> ''a) * ''a list -> ''a
Looks pretty straight-forward, it takes a function that works over equality types and a list of equality type as arguments, because of the xs = [] comparison. However, for some reason it works on input such as (op +, [2.3, 2.7, 4.0]), when in SML/NJ reals are not an equality type. Can anyone help me shed some light on why this magic occurs?
I believe it's to do with the magical way in which + is overloaded for reals. To me, this almost verges on being a compiler bug, although I would have to look at the SML97 definition to see exactly what the correct behaviour is meant to be. The overloading over + is something of a nasty dark corner in SML, IMHO.
For example, if you define a function that is of type real * real -> real and pass that as an argument to foldr2 you get the type error you were expecting:
fun f (x : real * real) = 134.5
foldr2 (f, [1.4, 2.25, 7.0])
stdIn:8.1-8.29 Error: operator and operand don't agree [equality type required]
You can even induce the type error if you just add a type annotation to op +, which basically led me to the conclusion that it is the overloading of + that is causing the mysterious effect.