I'm trying to implement a particular algorithm. The algorithm isn't very well described but I do have an OCaml implementation. Problem is I don't know OCaml and I'm finding the syntax strange. So here's the first of what might be many questions. Apologies for any mistakes in terminolgy.
One part of the code I have looks like this
type alternative_text = string
type indent = int
module Line =
struct
type t = {s:alternative_text; i:indent}
let make s i = {s;i}
let text (l:t): alternative_text = l.s
let length l = String.length l.s
let indent l = l.i
end
My question concerns the line let text (l:t): alternative_text = l.s. I think I know what this is, a function Line.text which takes a Line.t object and returns the s field, which is a string.
My question concerns the (l:t): alternative_text syntax. This looks like it's specifying the type of the parameter and function result, but why is it necessary? As far as I know let text l = l.s would do exactly the same thing and the other functions are defined without using this extra syntax. So why is it being used here?
Thanks in advance.
The problem with records is that their field names have a scope that's outside the record. So if you have two records with the same field name a, they will clash. I.e., it won't be possible in general to tell whether x.a refers to a field in one record type or the other record type. Depending on the type of x, it could be either.
OCaml tries to give a lot of flexibility in this area by inferring the record type (of x in this example). But if it can't be inferred you need to specify which type you're talking about.
As a side note #glennsl is correct. If you have a non-trivial amount of OCaml to figure out, and you're learning OCaml from scratch, it will be faster to learn OCaml from a book or an online tutorial than to ask individual questions here on StackOverflow.
Related
I have read some of this post Meaning of Alternative (it's long)
What lead me to that post was learning about Alternative in general. The post gives a good answer to why it is implemented the way it is for List.
My question is:
Why is Alternative implemented for List at all?
Is there perhaps an algorithm that uses Alternative and a List might be passed to it so define it to hold generality?
I thought because Alternative by default defines some and many, that may be part of it but What are some and many useful for contains the comment:
To clarify, the definitions of some and many for the most basic types such as [] and Maybe just loop. So although the definition of some and many for them is valid, it has no meaning.
In the "What are some and many useful for" link above, Will gives an answer to the OP that may contain the answer to my question, but at this point in my Haskelling, the forest is a bit thick to see the trees.
Thanks
There's something of a convention in the Haskell library ecology that if a thing can be an instance of a class, then it should be an instance of the class. I suspect the honest answer to "why is [] an Alternative?" is "because it can be".
...okay, but why does that convention exist? The short answer there is that instances are sort of the one part of Haskell that succumbs only to whole-program analysis. They are global, and if there are two parts of the program that both try to make a particular class/type pairing, that conflict prevents the program from working right. To deal with that, there's a rule of thumb that any instance you write should live in the same module either as the class it's associated with or as the type it's associated with.
Since instances are expected to live in specific modules, it's polite to define those instances whenever you can -- since it's not really reasonable for another library to try to fix up the fact that you haven't provided the instance.
Alternative is useful when viewing [] as the nondeterminism-monad. In that case, <|> represents a choice between two programs and empty represents "no valid choice". This is the same interpretation as for e.g. parsers.
some and many does indeed not make sense for lists, since they try iterating through all possible lists of elements from the given options greedily, starting from the infinite list of just the first option. The list monad isn't lazy enough to do even that, since it might always need to abort if it was given an empty list. There is however one case when both terminates: When given an empty list.
Prelude Control.Applicative> many []
[[]]
Prelude Control.Applicative> some []
[]
If some and many were defined as lazy (in the regex sense), meaning they prefer short lists, you would get out results, but not very useful, since it starts by generating all the infinite number of lists with just the first option:
Prelude Control.Applicative> some' v = liftA2 (:) v (many' v); many' v = pure [] <|> some' v
Prelude Control.Applicative> take 100 . show $ (some' [1,2])
"[[1],[1,1],[1,1,1],[1,1,1,1],[1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,1,"
Edit: I believe the some and many functions corresponds to a star-semiring while <|> and empty corresponds to plus and zero in a semiring. So mathematically (I think), it would make sense to split those operations out into a separate typeclass, but it would also be kind of silly, since they can be implemented in terms of the other operators in Alternative.
Consider a function like this:
fallback :: Alternative f => a -> (a -> f b) -> (a -> f e) -> f (Either e b)
fallback x f g = (Right <$> f x) <|> (Left <$> g x)
Not spectacularly meaningful, but you can imagine it being used in, say, a parser: try one thing, falling back to another if that doesn't work.
Does this function have a meaning when f ~ []? Sure, why not. If you think of a list's "effects" as being a search through some space, this function seems to represent some kind of biased choice, where you prefer the first option to the second, and while you're willing to try either, you also tag which way you went.
Could a function like this be part of some algorithm which is polymorphic in the Alternative it computes in? Again I don't see why not. It doesn't seem unreasonable for [] to have an Alternative instance, since there is an implementation that satisfies the Alternative laws.
As to the answer linked to by Will Ness that you pointed out: it covers that some and many don't "just loop" for lists. They loop for non-empty lists. For empty lists, they immediately return a value. How useful is this? Probably not very, I must admit. But that functionality comes along with (<|>) and empty, which can be useful.
First of all, since the question is somehow related to a school project I don't think that posting my code is appropriate. Plus, as I explain later on I only have a modified version of the code in question.
And I explain myself. I should implement a version of Dijkstra's algorithm using a priority queue. I thought that a simple functional way to do so is define a dijkstra function with inputs the queue and the targeted node and a helper function to enqueue the nodes that are neighbors to the element of the list that was just dequeued. Unfortunately, the helper function did't typecheck - Unresolved Flex Record.
So far it may seem that the code is important but allow me to add one more
detail. Since the graph was 4-canonical(meaning each node has exactly four neighbors) I represented it as a matrix using modulus arithmetic. In order to simplify my algorithm I used this fact to rewrite it and use 4 extra helper functions - one for each move possible - instead of four ifs inside the first helper function. Each of the four-move function returns true if we should visit this node (meaning the cost we will need this way is smaller than the current cost needed) and false if not. And the first helper simply returns a tuple of four booleans variables. Finally, I copied the enqueue code that wasn't working in my first try into the body of the dijkstra code and suddenly it did typecheck.
I understand that it may still be unclear and perhaps you can only speculated about what was going on. But I am truly very puzzled.I searched this site and SML basis as well and found that this kind of error occurs in the following case:
f (x,y,z) = ...
where z isn't used so the checker can't deduct what it is.
I am sure this is not the case in my problem since I just copy-paste the code(not a very good technique I know but ok). Hence, I concluded that the problem was the typechecker not working with functions calls. I searched again and found a Hindley Miller algorithm explanation. And from what I understood every time it encounters and a function will assume is a->b as the first step and later on will go to the definition of the function and complete the task. So I was back to square one and decided to ask this question here looking for a better understanding of type inference or for a hint of what has going on.
P.S. 1) Even though I tried my best to explain the question I it is still unclear or too broad let me know and I will delete,no problem.
P.S. 2) A smaller and simpler question: I read that #1 is not adviceable to take the 1st element of a tuple and sometimes it doesn't even typecheck
and instead it should be used pattern matching. Could you explain that?
P.S. 3) Someone may wonder why I asked this question since I solved the problem with my second try. Personally, I don't consider solved but hidden.
Thanks in advance and sorry for the size of the question.
Links:
SML/NJ Errors
P.S. 2)
Hindley-Miller
UPDATED: After some extra searching I have a guess about what was wrong. I was implementing a priority queue not customized for my problem but more general. So, the inference of the priority queue type was taking place when I first enqueued an element. But after enqueueing my source node and calling dijkstra the queue would be empty once more (my dijsktra was dequeueing the first element checking if it is the target node) and the first call of the helper function that add nodes would have an empty queue as one of its arguments. Perhaps the empty queue has no type and that was causing the error?
I'm taking a guess at what you're asking.
I have a function enqueue that does not work in one context, but it does work in another. Why? It uses the #1 macro, and I read that #1 is not adviceable to take the 1st element of a tuple and sometimes it doesn't even typecheck and instead it should be used pattern matching.
In Standard ML, #1 is a macro. It behaves like a function, but unlike functions, it is overloaded for any tuple/record with a 1 field in it. If you do not specify what kind of tuple you're passing to a function, using #1 will not disambiguate this. For example,
- fun f pair = #1 pair;
! Toplevel input:
! fun f pair = #1 pair;
! ^^
! Unresolved record pattern
But giving it the type (either through explicit type annotation, or in a context where the type can be inferred by other means) works well.
- fun f (pair : int * int) = #1 pair;
> val f = fn : int * int -> int
I don't know if I'd label #1 as a definite no-go and pattern matching as the only option, [edit: ... but this Stack Overflow answer that Ionuț G. Stan linked to has some arguments.]
There are advantages and disadvantages with both. Alternatively you can make unambiguous getters that only work on the type of tuple you're working with. For example,
fun fst (x, _) = x
fun snd (_, y) = y
I just started learning Erlang so please bear with me if this question seems a little simple.
Hi guys. I've been thinking about it for a while but nothing I come up with seems to be working.
I am writing an Erlang function that is supposed to take a list as an argument then print the list with my name in front of it. For the purposes of this question, let's say my name is "James".
If I type in testmodule:NameInFront("Legible", "Hey", "Think").
Erlang should return ["James", "Legible", "Hey", "Think"]
This is the code I have so far:
-module(testmodule).
-export([NameInFront/1]).
NameInFront(List)-> ["James"]++[List].
It works just fine when I type in just one word, which I guess it the fault of the NameInFront/1 part but I want it to be able to handle any amount of words I type in. Anyone know how I can get my function to handle multiple inputs? Thank you very much.
I'm not quite sure what you mean: whether you want your function to be variadic (take a flexible number of arguments), or you are having trouble getting your lists to join together properly.
Variadic functions are not the way Erlang works. FunctionName/Arity defines the concrete identity of a function in Erlang (discussed here). So our way of having a function take multiple arguments is to make one (or more) of the arguments a list:
print_terms(Terms) -> io:format("~tp~n", [Terms]).
The io:format/2 function itself actually takes a list as its second function, which is how it deals with a variable number of arguments:
print_two_things(ThingOne, ThingTwo) ->
io:format("~tp~n~tp~n", [ThingOne, ThingTwo]).
In your case you want to accept a list of things, add your name to it, and print it out. This is one way to do it.
name_in_front(ListOfStrings) ->
NewList = ["James" | ListOfStrings],
io:format("~p~n", [NewList]).
Using the ++ operator is another (which is actually a different syntax for a recursive operation which expands to the exact same thing, ):
name_in_front(ListOfStrings) ->
NewList = ["James"] ++ ListOfStrings,
io:format("~tp~n", [NewList]).
But that's a little silly, because it is intended to join two strings together in a simple way, and in this case it makes the syntax look weird.
Yet another way would be to more simply write a function that take two arguments and accomplishes the same thing:
any_name_in_front(Name, ListOfThings) ->
io:format("~tp~n", [[Name | ListOfThings]]).
The double [[]] is because io:format/2 takes a list as its second argument, and you want to pass a list of one thing (itself a list) into a single format substitution slot (the "~tp" part).
One thing to note is that capitalization matters in Erlang. It has a meaning. Module and function names are atoms, which are not the same thing as variables. For this reason they must be lowercase, and because they must be lowercase to start with the convention is to use underscores between words instead of usingCamelCase. Because, well, erlangIsNotCpp.
Play around in the shell a bit with the simple elements of the function you want, and once you have them ironed out write it into a source file and give it a try.
An OCaml module usually contains at least one abstract type whose idiomatic name is t. Also, there's usually a function that constructs a value of that type.
What is the usual / idiomatic name for this?
The StdLib is not consistent here. For example:
There's Array.make and a deprecated function Array.create. So that function should be named make?
On the other hand, there's Buffer.create but not Buffer.make. So that function should be named create?
Some people find this way of module design makes OCaml programming easier, but this is not a mandatory OCaml programming style, and I do not think there is no official name for it. I personally call it "1-data-type-per-1-module" style. (I wrote a blog post about this but it is in Japanese. I hope some autotranslator gives some useful information to you ...)
Defining a module dedicated to one data type and fix the name of the type t has some values:
Nice namespacing
Module names explain about what its type and values are, therefore you do not need to repeat type names inside: Buffer.add_string instead of add_string_to_buffer, and Buffer.create instead of create_buffer. You can also avoid typing the same module names with local module open:
let f () =
let open Buffer in
let b = create 10 in (* instead of Buffer.create *)
add_string b "hello"; (* instead of Buffer.add_string *)
contents b (* instead of Buffer.contents *)
Easy ML functor application
If an ML functor takes an argument module with a data type, we have a convention that the type should be called t. Modules with data type t are easily applied to these functors without renaming of the type.
For Array.create and Array.make, I think this is to follow the distinction of String.create and String.make.
String.create is to create a string with uninitialized contents. The created string contains random bytes.
String.make is to create a string filled with the given char.
We had Array.create for long, to create an array whose contents are filled with the given value. This behavior corresponds with String.make rather than String.create. That's why it is now renamed to Array.make, and Array.create is obsolete.
We cannot have Array.create in OCaml with the same behaviour of String.create. Unlike strings, arrays cannot be created without initialization, since random bytes may not represent a valid OCaml value for the content in general, which leads to a program crash.
Following this, personally I use X.create for a function to create an X.t which does not require an initial value to fill it. I use X.make if it needs something to fill.
I had the same question when I picked up the language a long time ago. I never use make and I think few people do.
Nowadays I use create for heavy, often imperative or stateful values, e.g. a Unicode text segmenter. And I use v for, functional, lighter values in DSL/combinator based settings, e.g. the various constructors in Gg, for example for 2D vectors, or colors.
As camlspotter mentions in his answer the standard library distinguishes make and create for values that need an initial value to fill in. I think it's better to be regular here and always use create regardless. If your values support an optional initial fill value, add an optional argument to create rather than multiply the API entry points.
I am trying to solve an exercise in SML like ;
Write an ML program to be used for a multiple choice exam containing 10 questions. Your program should include the following:
o The answer key of the exam
e.g.
val key= “adabcbaadb”;
o Type definition for a record (info) which contains name and answers of a student.
e.g. {name=”Ali”,ans=”abadccdadb”}
o Type definition for a tuple (result) which contains name and score of a student.
e.g. ("Ali",60)
o Write as many functions as needed to take a list of records of type info containing the information of 3 students, calculate their scores, and convert them into a list of tuples of type result. You can write other supporting functions as well
e.g.
- val stuInfo:info list=[{name=”Ali”,ans=”abadccdadb”},
{name=”Ege”,ans=”cbbdacabda”},
{name=”Can”,ans=”adabcbaadb”}];
- val results = calculate(stuInfo);
val results = [("Ali",60),("Ege",20),("Can",100)] : result list
o Write as many functions as needed to calculate the average score, and return the students who received a score above the average.
e.g.
-val aboveList=aboveAvg(results);
val aboveList = [("Ali",60),("Can",100)] : result list
Notes:
Make sure you give the types of your parameters and return value in all your functions.
Paranthesize your expressions.
Use explode function which converts a string to a character array
e.g.
- explode "abc";
val it = [#"a",#"b",#"c"] : char list
My written code for this exercise is below ; but my code is not working :/ Where is my mistake ?
val answer_key="ddacbadbca";
type student_information={s_name:string,s_choice:string};
type student_result=string*int;
val student:info list=[{s_name="David",s_choice="adcbbaccad"},{s_name="John",s_choice="ccdabdbbcc"},{s_name="Alice",s_choice="abdaccacdb"}];
val 3studentsResult:student_result=average(student_information);
fun average ((h::t):student_information list):student_result list=student_score(explode"#ans h",explode"key")::average(t);
val sum=0;
fun student_score(((a::b,c::d):'a list):'a list) = (if(a=c) then sum=sum+10 else sum=sum+0 )::student_score(b,d);
Thanks
There are multiple issues about this code. Before starting, I should recommend you to work on your styling, you can use some spaces and extra lines between functions to see what you are doing easily, like this:
val answer_key = "ddacbadbca";
type student_information = {s_name:string, s_choice:string};
type student_result = string * int;
val student : student_information list =
[{s_name="David", s_choice="adcbbaccad"},
{s_name="John", s_choice="ccdabdbbcc"},
{s_name="Alice", s_choice="abdaccacdb"}];
You might also want to keep your variable and type names consistent. I think the convention is to use snake case (like snake_case) for type names and camel case (like camelCase) for variable and function names.
Here are some of your actual mistakes:
For your student variable, you give the type info list, which doesn't exist in your program. I assume your student_information variable used to be named info, so you should change one of those to the other.
You have a variable named 3studentsResult. Variables cannot start with numbers, they have to start with letters. You have to rename that variable, to something like threeStudentsResult.
In your 3studentsResult variable, you are using the average function that you define later. That doesn't work in Standard ML. You should define a function before using it. (Unless you need mutual recursion, you can use the and keyword then, but it's irrelevant to your problem.) Therefore, define average before 3studentsResult, and define student_score before average.
Even after fixing these, your student_score function is incorrect. I assume sum=sum+10 means that you are trying to change sum's value, like you would do in an imperative programming language. However, Standard ML is a functional language and changing values of variables is something you should avoid in functional programming. In fact, when I talk about "variables" in SML, I mean value declarations that cannot be changed. I recommend you to think about your problem a little bit more and maybe you can divide your problem into sub-problems. Good luck.