I have a very basic question regarding OCaml records. Suppose I have a record defined:
type r = {a: int; b: int; c: int}
let x = {a=3; b=8; c=2}
Now, suppose I want to create a new record which has all fields equal to x but which has c=4. I could write:
let y = {a=3; b=8; c=4}
but this is annoying because there's not need to re-write a=3 and b=8. I could also write:
let y = {a=x.a; b=x.b; c=4}
but this is still not good if the record has many fields. Is there any way of writing something like:
let y = {x with c=4}
or something of the sort?
yeah, and that's the exact syntax.
let y = {x with c=4}
Related
I'm just starting to learn Rust and I'm coming from an OCaml background.
One thing that I often use is nested let expressions, in order to group related code together.
let x =
let y = 42 in
y + 1
in
...
My naive translation of this to rust would be:
let x =
let y = 42;
y + 1
;
However this fails to compile.
Is this type of syntax possible, or is it heavily frowned upon and thus is not supported?
Rust uses curly braces to delimit scopes. This works fine:
let x = {
let y = 42;
y + 1
};
Working on an exercise for university class and cant seem to represent what I am trying to do with correct syntax in ocaml. I want the function sum_positive to sum all the positive integers in the list into a single int value and return that value.
let int x = 0 in
let rec sum_positive (ls: int list) = function
|h::[] -> x (*sum of positive ints in list*)
|[] -> 0
|h::t -> if (h >= 0) then x + h then sum_positive t else sum_positive t (*trying to ensure that sum_positive t will still run after the addition of x + h*)
On compiling I am met with this error,
File "functions.ml", line 26, characters 34-38:
Error: Syntax error
This points to the then then statement I have in there, I know it cannot work but I cant think of any other representations that would.
You have if ... then ... then which is not syntactically valid.
It seems what you're asking is how to write what you have in mind in a way that is syntactically valid. But it's not clear what you have in mind.
You can evaluate two expressions in OCaml sequentially (one after the other) by separating them with ;. Possibly that is what you have in mind.
However it seems to me your code has bigger problems than just syntax. It appears you're trying to use x as an accumulated sum for the calculation. You should be aware that OCaml variables like x are immutable. Once you say let x = 0, the value can't be changed later. x will always be 0. The expression x + h doesn't change the value of x. It just evaluates to a new value.
The usual way to make this work is to pass x as a function parameter.
I was getting an issue that had involved the parameter of , I believe it was because I was trying to add an int value to function of type int list. This is what I ended up with.
let rec sum_positive = function
|[] -> 0
|h::t -> if h > 0 then h + (sum_positive t) else sum_positive t
a lot simpler than I thought it out to be.
I'm trying to solve the following system:
gx:=2*x*exp(x^2+y^2)-4*y
gy:=2*y*exp(x^2+y^2)-4*x
sys:={gx=0,gy=0}:
solve(sys,{x,y})
It then displays the following output:
{x = 0, y = 0}, {x = RootOf(2*_Z^2-ln(2)), y = RootOf(2*_Z^2-ln(2))}, {x = -RootOf(2*_Z^2-ln(2)-I*Pi), y = RootOf(2*_Z^2-ln(2)-I*Pi)}
The first "root" (0,0) is correct, however how do i remove that root of and whatever Z that is? Is it possible to get the correct answer out of it?
This is a great scenario for the function allvalues.
From the help page:
compute all possible values of expressions involving RootOfs
gx:=2*x*exp(x^2+y^2)-4*y;
gy:=2*y*exp(x^2+y^2)-4*x;
sys:={gx=0,gy=0}:
sol := solve(sys,{x,y}):
seq(allvalues(sol[i]), i= 1..numelems([sol])):
print~([%])[];
Notice, however, that you are not getting all solutions this way. There are infinitely many solutions to the problem; to get all solutions, use the optional argument allsolutions = true in the solve command:
sol2 := solve(sys,{x,y},allsolutions = true):
seq(allvalues(sol2[i]), i= 1..numelems([sol2])):
print~([%])[];
If you run this, you will see a new variable _Z1 that has a trailing tilde (~) - this tilde means there are assumptions on the variable. To see these assumptions use
about(_Z1);
Originally _Z1, renamed _Z1~:
is assumed to be: integer
This means that the above solutions work for any integer _Z1. Those are all your solutions and written in the expected way.
You can use fsolve to final numerical solutions,
restart;
gx:=2*x*exp(x^2+y^2)-4*y;
gy:=2*y*exp(x^2+y^2)-4*x;
sys:={gx=0,gy=0}:
fsolve(sys,{x,y})
{x = .5887050113, y = .5887050113}
sys:={gx=0.,gy=0.}:
solve(sys,{x,y})
{x = 0., y = 0.}, {x = .5887050112, y = .5887050112}, {x = -.5887050112, y = -.5887050112}, {x = -.9887236333-.7943556085*I, y = .9887236333+.7943556085*I}, {x = .9887236333+.7943556085*I, y = -.9887236333-.7943556085*I}
For example I have the following,
type something = (Float, Float, Int, Aa, Bb, Cc, Int)
If I were to desire to find the smallest something in base to their first element (Float) how could I do that? The way I have reasoned it is the following, yet I cant manage to figureout how to implement it
Because I have a list of somethings the easiest way should be to create my own min helper function that compares 2 somethings and returns the smallest of the two. However it is trying to do that "easier way" that got me stuck with type compile errors...
findMin :: something -> something -> somthing
findMin x y = sortBy (compare `on` fst) x y
I am not familiar with sortBy and compare on, I just came across a similar question here in SO but I couldnt manage to make it work. As a beginner in Haskell, is there another way to approaching this?.
If you want to compare based on the first field of a data type, you can let Haskell write the code for you:
data Something = Something Float Float Int String Bool Char Int
deriving (Eq, Ord)
The deriving clause specifies which type classes implementations are automatically generated for the Something type. Here, we derive Eq which allows us to ask whether two Somethings are equal (e.g., with ==), and Ord, which allows us to compare two Somethings and know which one is "greater".
Haskell's default behavior when deriving Ord is to compare each field from first to last, so the default code will start by comparing the first Float of each Something, which is exactly what you want.
Once you're dealing with a type that implements Ord, you can use all sorts of built-in functions like minimum :: Ord a => [a] -> a. This takes a list of any type that implements Ord, and gives back the smallest element. So, as an example:
st1 = Something 3.14 2.72 7 "hello" False 'λ' 42
st2 = Something 3.15 2.72 7 "hello" False 'λ' 42
smallest = minimum [st1,st2]
Using a custom data type is usually the better option, but if you really want to use tuples, you can start by defining a helper function comparingFst that compares based on the first element of the tuple.
import Data.Ord
import Data.List
-- Dummy data types for example purposes. Derive from Show just so
-- that the example can be more easily tested interactively in ghci.
data Aa = Aa deriving Show
data Cc = Cc deriving Show
type Something = (Float, Float, Int, Aa, Cc, Int)
comparingFst :: Something -> Something -> Ordering
comparingFst = comparing fstSomething
where fstSomething (x,_,_,_,_,_) = x
Now you can take the smaller of two elements with:
findMin :: Something -> Something -> Something
findMin x y = case comparingFst x y of
LT -> x
_ -> y
or from a list of elements
findMinimum :: [Something] -> Something
findMinimum = minimumBy comparingFst
And you can also use the same helper function for sorting:
sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy comparingFst
Also, it's worth mentioning that tuples are, by default, compared element-wise, starting from the first element, so assuming your Aa and Bb types can be derived from Ord and Eq, you don't need anything extra, i.e. the example becomes:
import Data.List
data Ab = Ab deriving (Show, Ord, Eq)
data Cc = Cc deriving (Show, Ord, Eq)
type Something = (Float, Float, Int, Ab, Cc, Int)
findMin :: Something -> Something -> Something
findMin x y = min x y
findMinimum :: [Something] -> Something
findMinimum = minimum
sortSomethings :: [Something] -> [Something]
sortSomethings = sort
In other words, you can just use the standard min and sort functions as-is.
You have some syntax errors, firstly.
There are two things you can do. Firstly, following the model of using an accessor function to get at the field you want (fst), we can define labels for the fields of your type:
data Something = Something { field_x, field_y :: Float,
field_z :: Int }
and then sort on field_x
import Data.List
import Data.Function
sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy (compare `on` field_x)
getting at the mimimum is the same as taking the head off the sorted list:
minSomethings :: [Something] -> Something
minSomethings = head . sortSomethings
alternatively, you can write a custom Ord instance for the Something type that compares values only using field_x, then regular sort and minimum (and other Ord-based functions), will "just work".
I have a list of String that are in the form of XxX where X are numbers up to 4 digits long(they are image sizes in (pixels)x(pixels)).
For example:
["192x192","64x84","96x96","64x64","292x192","32x32","64x12"]
Using a function mySort which is just insertion sort that looks only at the number up to x:
mysort [] = []
mysort [x] = [x]
mysort (x:xs) = insert (mysort xs)
where insert [] = [x]
insert (y:ys) | takeUntilX x <= takeUntilX y = x : y : ys
| otherwise = y : insert ys
I get this:
["192x192","292x192","32x32","64x84","64x64","64x12","96x96"]
Which is only partly sorted, all of the sorted "64x**" remaing in they original order but I want them also to be sorted so I get this:
["192x192","292x192","32x32","64x12","64x64","64x84","96x96"]
What would be a better solution - modifying function mySort or writing a new function that sorts the partially sorted list?
Can you give me the the basic idea how I could do either?
import Data.List
import Data.List.Split
res = map (intercalate "x") . sort . map (splitOn "x")
I'm using Data.List.Split from http://hackage.haskell.org/package/split
For future needs in mind, you could also:
1. convert your data to tuples e.g. (64, 64)
2. use builtin sort. It does exatly what you want
I would assume that in the future you will use the data as integers, so converting them as early as possible could save you a lot of trouble in the future.
br,
Juha
EDIT: Corrected -- I've figured out what you meant.
I'd separate out the concerns -- (1) parse the strings to get the dimensions; (2) sort the dimensions however you see fit; (3) convert the dimensions back to strings. In other words:
import List
stringToDim :: String -> (String,String)
stringToDim s = (a,c)
where (a,b) = break (== 'x') s
c = drop 1 b
dimToString :: (String,String) -> String
dimToString (x,y) = x ++ "x" ++ y
dimsort :: [String] -> [String]
dimsort = map dimToString . sort . map stringToDim
Ok, here is the final solution I'm happy with although it isn't what I originaly asked for. Modified copy from max taldykin:
res x = map (intercalate "x") $ map myshow $ sort $ map (readAsInt) $ map (splitOn "x") x
readAsInt [x,y] = [read x :: Int, read y ::Int]
myshow [x,y] = [show x, show y]
input: ["192x192","64x184","96x96","64x64","292x192","32x32","64x12"]
output: ["32x32","64x12","64x64","64x184","96x96","192x192","292x192"]
Although it does't give ["192x192","292x192","32x32","64x12","64x64","64x184","96x96"] it is still ok for what I had in mind.