I'm playing around a little with F# syntax.
In Sweden we have a game called "Backslang" (googletranslated from "Rövarspråk")
The rules are quite simple. All words you say must be said in a specific way. While vocals are the same, each consonant must be pronounced with an "o" followed by the consonant again.
I.e. "L" would be "LOL", "FRIDAY" would be
"FOFRORIDODAY" and "BALL" would be "BOBALOLLOL".
I wrote some code that looks really stupid but does its job.
let myWord (x:string) =
x.Replace("q","qoq").Replace("w","wow").Replace("r","ror").Replace("t","tot").Replace("p","pop").Replace("s","sos").Replace("d","dod").Replace("f","fof").Replace("g","gog").Replace("h","hoh").Replace("j","joj").Replace("k","kok").Replace("l","lol").Replace("z","zoz").Replace("x","xox").Replace("c","coc").Replace("v","vov").Replace("b","bob").Replace("n","non").Replace("m","mom").Replace("Q","QOQ").Replace("W","WOW").Replace("R","ROR").Replace("T","TOT").Replace("P","POP").Replace("S","SOS").Replace("D","DOD").Replace("F","FOF").Replace("G","GOG").Replace("H","HOH").Replace("J","JOJ").Replace("K","KOK").Replace("L","LOL").Replace("Z","ZOZ").Replace("X","XOX").Replace("C","COC").Replace("V","VOV").Replace("B","Bob").Replace("N","Non").Replace("M","Mom").ToLower()
myWord "ball"
F# Interactive: val it : string = "bobalollol"
For the sake of readability, is there any way to give this code a better look?
I'm a newbie to F# and Functional Programming so any advices, protips and pointers are warmly welcome!
Perhaps something like this:
let isVowel = function
| 'a' | 'e' | 'i' | 'o' | 'u' | 'y' | 'å' | 'ä' | 'ö'
| 'A' | 'E' | 'I' | 'O' | 'U' | 'Y' | 'Å' | 'Ä' | 'Ö' -> true
| _ -> false
let lollify s =
[| for c in s do if isVowel c then yield c else yield c; yield 'o';yield c |]
|> System.String
[<EntryPoint>]
let main argv =
printfn "%A" <| lollify "Ball"
0
Note; this also has the benefit of not creating alot of temporary string objects.
Another option would be this:
let lollify s =
s
|> Seq.map (fun c -> if isVowel c then [|c|] else [|c;'o';c|])
|> Seq.collect id
|> Seq.toArray
|> System.String
String.collect (string >> function
| vowel when "aeiouyåäöAEIOUYÅÄÖ".Contains vowel -> vowel
| consonant -> consonant + "o" + consonant )
String.collect applies a function to each char of a string.
Related
let rec createSentence(list) = (
match list with
case [] -> failwith "błędna lista"
| case [_] -> List.hd list
| case [_,_] -> List.hd list ^ createSentence(List.tl list)
| case _ -> List.hd list ^ " " ^ createSentence(List.tl list);;
);;
Ocaml returns a Syntax error: operator expected. I have no idea how to move forward with this
The pattern-matching in OCaml has the following syntax,
match <expr> with
| <pattern1> -> <action1>
| <pattern2> -> <action2>
...
e.g.,
match ["hello"; "world"] with
| [word1; word2] -> print_endline (word1 ^ word2)
| _ -> assert false
Also, note that the list elements in OCaml are separated with ;
I would suggest reading the Introduction to OCaml or some OCaml book
Update: to make it more clear, there is no case keyword in OCaml and you shouldn't write case before a pattern, i.e., instead of | case [], just write | [].
How can I write a function in Ocaml, that would accept two boolean values (for instance a and b, that would represent logical values 0 and 1) and a character, that would determine the operation between these two logical values? The function would then return true or false, depending on the corresponding logical value input.
There is both a semantic, as well as a syntax error in this code; well, maybe there are more, but the compiler only made a complaint about this one so far:
line 2, characters 27-30:
Error: This expression has type char but an expression was expected of type
bool
This is what the compiler has stated about the code and here's what I've wrote:
let logic (a, b) operation = match operation with
| true -> if (operation == 'A') then match (a,b) with
| (true, true) -> true
| _ -> false
else if (operation == '0') then match (a,b) with
| (false,false) -> false
| _ -> true
else if (operation == 'X') then match (a,b) with
| (true,true) -> false
| (false,false) -> false
| _ -> true
else if (operation == 'I') then match (a,b) with
| (true, false) -> false
| _ -> true
else then match (a,b) with
| _ -> false
| false -> end;;
logic (a,b) 'A';;
--------------------------------------------------------------------------
OK, I've made some progress,at least it compiles now. However I still get an error, when I try to call the "logic" function with this line:
logic (true, false) 'A';;
The error states this:
Error: This expression has type bool
This is not a function; it cannot be applied.
Here's what I wrote now:
let logic (a, b) operation = match operation with
| 'A' -> (match (a,b) with
| (true, true) -> true
| _ -> false
)
| '0' -> (match (a,b) with
| (false,false) -> false
| _ -> true
)
| 'X' -> (match (a,b) with
| (true,true) -> false
| (false,false) -> false
| _ -> true)
| 'I' -> (match (a,b) with
| (true, false) -> false
| _ -> true
)
| _ -> (match (a,b) with
| _ -> false
)
To expand on the comment of #Elan-Hamburger a little bit.
You have this:
match operation with
| true -> ...
But your operation is a character. So this won't work. You can only match operation against specific characters.
It's especially strange since you later compare operator to various characters using ==. But the match will do that for you.
In other words you can have something like this:
match operation with
| 'A' -> ...
| '0' -> ...
| 'X' -> ...
| 'I' -> ...
| _ -> ...
There are many other problems with your code. Here are some comments:
You have nested match statements, which requires parentheses to work out right. If you try to nest without parentheses there's no way to tell when the inner match is over and further alternatives (starting with |) of the outer match are given.
Nested match statements look like this:
match expr with
| X ab ->
(match ab with
| A -> 4
| B -> 2
)
| Y _ -> 0
(You can also use begin/end instead of parentheses if you prefer the way that looks.)
You're using == to compare values. The ordinary equality comparison operator is =. The special operator == should only be used when you have a specific reason for it.
You have code that reads like this:
else then match ...
This can't be syntactically correct. Possibly the then is left over from an edit.
You can simplify this expression
match (a, b) with
| _ -> false
to this simpler expression:
false
Update
I can't reproduce your new reported problem. In fact your new code works OK for me in two quick tests.
. . .
val logic : bool * bool -> char -> bool = <fun>
# logic (true, false) 'A';;
- : bool = false
# logic (true, true) 'A';;
- : bool = true
Possibly there was some extraneous input (or extraneous definitions) in your top-level session. I suggest just trying again with a fresh session.
I'm trying to figure out how to pattern match with user defined types. For example I have this type.
Type custom_type = B of bool | I of int | S of string | C of custom_type * custom_type
I want to pattern match these types, and say for example count the number of ints in a value. Example value:
C(C(B true, I 5), C(S "example", B false))
I think I'm very close to figuring it out, I know I need to use wildcards but I can't write out every instance there could be, because there are numerous varying values I need to check.
Thanks!
Edit: Code that isn't working:
let num = 0
let rec count_ints (c: custom_type):int =
match c with
| C (I(_), _) -> num + 1
| C (_, I(_)) -> num + 1
| C (C(_), _) -> count_ints c
| C (_, C(_)) -> count_ints c
You should be thinking of having 4 cases in your function, one for each constructor. You don't need to match what's inside these constructors because you can call yourself recursively to handle that.
Your code calls count_chars, but there's no function of that name. If it's supposed to be count_ints, then this is not a good recursive call. You must call recursively on a smaller problem. If you just pass c along to yourself recursively you'll get infinite recursion.
let rec count_ints (c: custom_type):int =
match c with
| I _ -> 1
| C (c1,c2) -> count_ints c1 + count_ints c2
| _ -> 0
In the following function, which reverses an array/list:
let rec rev l =
match l with
[] -> []
| h::t -> rev t # [h];;
One will notice that there is a pipe | before the following line:
h::t -> rev t # [h];;
I was wondering if anyone would be kind enough to explain what the purpose of this vertical bar | is in OCaml, and perhaps other uses? Thank you.
In your example it serves as a pattern separator for a multiple selection statement, sorta like the case of a switch statement in C like languages.
let is_vowel c = match c with
'a' | 'e' | 'i' | 'o' | 'u' -> true
| _ -> false ;;
function is_vowel(c){
switch(c){
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
These 2 pieces of code would generate the same output, however this is where the similarity's end. I found this documentation to be very helpful, it go's more into detail what else you can or cannot do with match.
Other uses of the pipe operator are:
enumerated type declaration
type typ = N1 | N2 | N3
union type declaration
type typ = N1 of typ1 | N2 of typ2
It separates the pattern match cases.
So, I have homework and I'm doing my best to solve it.
We have to translate from English to Morse code.
Every word has to be separated.
Example: if I enter this is it should write: ["_";"....";"..";"..."]["..";"...."]
I wrote 2 functions so far (lowercase to uppercase and matching letters and numbers with Morse code) and now I need to write function which converts string to a list of list of characters like this:
stringSAllCaps " ban an a ";;
- : char list list = [['B'; 'A'; 'N']; ['A'; 'N']; ['A']]
stringSAllCaps "banana";;
- : char list list = [['B'; 'A'; 'N'; 'A'; 'N'; 'A']]
I know how to convert a string into a list of characters, but have no idea what to do next. I don't need someone to solve that for me completely, just to guide me in right direction.
This is what I have done:
let explode niz =
let rec exp a b =
if a < 0 then b
else exp (a - 1) (niz.[a] :: b) in
exp (String.length niz - 1) []
;;
edit:
ty for your help :)
I've managed to solve this problem, but not like this. I will post it later.
as I solved it and continued with my homework I realized that I had to use while and pointers and now I'm stuck again (pointers are not my best friends.. ). Any suggestions?
my solution at the moment:
# let explode str =
let rec exp = function
| a, b when a < 0 -> b
| a, b -> exp (a-1, str.[a]::b)
in
exp ((String.length str)-1, []);;
# let split lst ch =
let rec split = function
| [], ch, cacc', aacc' -> cacc'::aacc'
| c::lst, ch, cacc', aacc' when c = ch -> split (lst, ch, [], cacc'::aacc')
| c::lst, ch, cacc', aacc' -> split (lst, ch, c::cacc', aacc')
in
split (lst, ch, [], []);;
I guess you should start by:
Renaming the arguments of your recursive function to have a more explicit meaning (as index and current_word for instance)
Adding a new parameter in you recursive function to store the words already seen (seen_words)
testing whether niz.[a] is a blank char and do the right things if it is the case ie. update the current word or the already seen list of words.