To keep structures clear is it possible to name them. So essentially I asking for a 'struct' in Rascal. So eg:
list[tupple[map[str,int],int]]
to:
treeLabel :: str
occurences :: int
treeData :: map[treeLabel,int]
treeNode :: tupple[treeData,int]
tree :: list[treeNode]
tree x=[];
Tx
Jos
How about using Abstract Data Types?
See Rascal Tutor. The above could then look like this:
data MyStruct = ms(str treeLabel,
int occurrence,
map[treeLabel, int] treeData,
tuple[TreeData td, int n] treeNode,
list[TreeNode] tree);
given some variable m with a myStruct value you can access elements with the usual dot notation:
m.treeLabel;
m.treeLabel = "xyz";
etc.
Related
For a class I'm following, I have to do the following exercise:
Implement a function
let splitAt (i : int) (l : List<'a>) : List<'a> * List<'a> = ...
that splits the list into two lists, the rst one containing all the elements of l from position 0 to position i
included, and the second one containing all the remaining elements. The two resulting lists are returned
in a tuple. For example:
split 3 [3;5;4;-1;2;2] = ([3;5;4;-1],[2;2])
We have to do these problems only using functional programming, and thus I'm not allowed to use pre-existing functions.
I have the following code which seems to me to (logically) be correct:
let splitAt (i:int)(l: List<'a>): List<'a> * List<'a> =
let rec loop n startlist restlist =
if n = i then
restlist * startlist
else
match startlist with
| h :: t -> loop (n+1) [t] [(restlist :: h)]
| h :: [] -> None
loop 0 l []
and below my [<EntryPoint>]
printfn "%A" (splitAt stringlist 3)
However, this gives me a couple of errors, namely:
None of the types 'a list, 'a list support the operator *
This expression was expected to have type int but here has type char list
This expression was expected to have type List<'a> but here has type int
The * operator is used for declaring a tuple type, but when you're building a tuple you use , instead. So you want restlist, startlist.
Then you'll discover that there's another type error, because one branch of your match expression returns None. That's an option type, so the value you return should be a Some. So you want Some (restlist, startlist).
And now you'll discover one more type error, which is that you've declared that the function returns a tuple but in fact it returns a tuple option (that is, either None or Some tuple). So your type declaration needs to become (List<'a> * List<'a>) option.
For more on why * is used in declaring tuple types rather than ,, https://fsharpforfunandprofit.com/posts/tuples/ is a good read.
Given some concrete syntax value, how I can I map it to a different type of value (in this case an int)?
// Syntax
start syntax MyTree = \node: "(" MyTree left "," MyTree right ")"
| leaf: Leaf leaf
;
layout MyLayout = [\ \t\n\r]*;
lexical Leaf = [0-9]+;
This does not work unfortunately:
public Tree increment() {
MyTree tree = (MyTree)`(3, (1, 10))`;
return visit(tree) {
case l:(Leaf)`3` => l + 1
};
}
Or is the only way to implode into an ADT where I specified the types?
Your question has different possible answers:
using implode you can convert a parse tree to an abstract tree. If the constructors of the target abstract language expect int, then lexical trees which happen to match [0-9]+ will be automatically converted. For example the syntax tree for syntax Exp = intValue: IntValue; could be converted to constructor data Exp = intValue(int i); and it will actually build an i.
in general to convert one type of values to another in Rascal you write (mutually) recursive functions, as in int eval (MyTree t) and int (Leaf l).
if you want to actually increment the syntactic representation of a Leaf value, you have to convert back (parse or via a concrete pattern) from the resulting int back to the Leaf.
Example:
import String;
MyTree increment() {
MyTree tree = (MyTree)`(3, (1, 10))`;
return visit(tree) {
case Leaf l => [Leaf] "<toInt("<l>") + 1>";
};
}
First the lexical is converted to a string "<l>", this is then parsed as an int using toInt() and we add 1 using + 1 and then map the int back to a string "< ... >", after which we can call the Leaf parser using [Leaf].
I am trying to iterate through an IDictionary (reasons explained later...) in F#, and round each value to a specified precision. Essentially this is what I'm trying to do:
List.iter (fun(x) -> a.Item(x) <- Math.Round(a.Item(x), input.precision)) (ICollectionToDoubleList a.Keys)
(where ICollectionToDoubleList takes the ICollection a.Keys and casts it to a double list).
However since you can't alter mutable variables inside closures, this doesn't compile.
My first attempt at a solution was this:
List.iter (fun(x) -> let p = Math.Round(a.Item(x), input.precision)
a.Item(x) := p
) (ICollectionToDoubleList a.Keys)
However I'm getting the error:
This expression was expected to have type
'a ref
but here has type
double
on a.Item(x)
I could convert the IDictionary into two lists (or a list of tuples), perform the rounding, and re-cast into an IDictionary, but this seems a bit messy and convoluted.
Any guidance greatly appreciated.
EDIT:
I forgot to mention a was defined as:
let mutable (a : IDictionary<double,double>) = ...
I think you want
a.Item(x) <- p
In F# you use <- to assign to mutable values, whilst := assign to ref values.
You could even use
a.[x] <- p
for a slightly simpler version.
Explaination of what mutable means (it behaves like the opposite of const in C)
let mutable m = [|1|]
let t = [|1|]
m.[0] <- 0
t.[0] <- 0 //neither of these change m or t - only elements so they are fine
m <- [|1;2;3;|] //fine as m is mutable
t <- [|1;2;3;|] //not allowed as t is not mutable
If you are used to const in C, the above are roughly equivalent to
int* m = {1};
const int* t = {1}
note, neither is equivalent to
const int* q const = {1}
which is I think what you thought not mutable meant.
Ok so I've discovered the answer...
I have defined a as:
let mutable (a : IDictionary<double,double>) = ...
If I change this to
let (a : IDictionary<double,double>) = ...
then this compiles. It seems a little counter-intuative to me that a non-mutable value can be mutated, but a mutatable variable cannot!!
Could someone please show me why the function below expects integer[] instead of byte[]
type Node =
| InternalNode of int*Node*Node
| LeafNode of int * byte
let weight node =
match node with
|InternalNode(w,_,_) -> w
|LeafNode(w,_)-> w
let createNodes inputValues =
let getCounts (leafNodes:(int*byte)[])=
inputValues |>Array.iter
(fun b-> let (w,v) =leafNodes.[(int)b]
leafNodes.[(int)b]<-(w+1,v))
leafNodes
[|for b in 0uy..255uy -> (0 ,b)|] |>getCounts
|>List.ofArray
|>List.map LeafNode
The only place that tells the F# compiler something about the type of the parameter is inside the lambda function given to Array.iter (from the use of this higher-order function, the compiler infers that you're working with arrays). Inside the lambda function you have:
leafNodes.[(int)b]
As a side-note, int in this code is just a normal F# function (not a special type cast construct), so the usual way to write it would be just:
leafNodes.[int b]
Now, the compiler knows that b (that is, values of the array given as the argument) can be converted to integer, however the int function works with other types (you can write for example int 3.13f. In ambiguous cases like this, the compiler uses int as the default type, so that's the reason why you're seeing a type int[].
You can add type annotations to the declaration like this (and it will work without any other changes, because byte can be converted to integer using the int function):
let createNodes (inputValues:byte[]) =
// ...
I am writing a custom read function for one of the data types in my module. For eg, when I do read "(1 + 1)" :: Data, I want it to return Plus 1 1. My data declaration is data Data = Plus Int Int. Thanks
This sounds like something better suited to a parser; Parsec is a powerful Haskell parser combinator library, which I would recommend.
I'd like to second the notion of using a parser. However, if you absolutely have to use a pattern-matching, go like this:
import Data.List
data Expr = Plus Int Int | Minus Int Int deriving Show
test = [ myRead "(1 + 1)", myRead "(2-1)" ]
myRead = match . lexer
where
match ["(",a,"+",b,")"] = Plus (read a) (read b)
match ["(",a,"-",b,")"] = Minus (read a) (read b)
match garbage = error $ "Cannot parse " ++ show garbage
lexer = unfoldr next_lexeme
where
next_lexeme "" = Nothing
next_lexeme str = Just $ head $ lex str
You could use GHC's ReadP.