Are there any modules or functions for dealing with trees? I have a type that looks like this:
type t =
Leaf of string (* todo: replace with 'a *)
| Node of string * t list
I'm struggling to do insertion, removal of subtrees, etc.
I've used Google but can't find anything.
Read the implementation of module Set in the sources of the OCaml standard library.
They are implemented with binary trees, only a little more sophisticated than yours.
(I would recommend you start with binary trees instead of having a list of children as you seem to have defined)
In the past, I've used ocamlgraph.
This is not a trivial lib to use, but if you need to insert nodes and change path, that could the trick, I've never used that in a b-tree context though...
And extracted from the language documentation:
The most common usage of variant types
is to describe recursive data
structures. Consider for example the
type of binary trees:
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btree;;
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
This definition reads as follow: a
binary tree containing values of type
'a (an arbitrary type) is either
empty, or is a node containing one
value of type 'a and two subtrees
containing also values of type 'a,
that is, two 'a btree.
Operations on binary trees are
naturally expressed as recursive
functions following the same structure
as the type definition itself. For
instance, here are functions
performing lookup and insertion in
ordered binary trees (elements
increase from left to right):
#let rec member x btree =
match btree with
Empty -> false
| Node(y, left, right) ->
if x = y then true else
if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
#let rec insert x btree =
match btree with
Empty -> Node(x, Empty, Empty)
| Node(y, left, right) ->
if x <= y then Node(y, insert x left, right)
else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>
Hope this helps
Related
I want to declare ahead of time the value type for a map type.
The functor Map.Make returns a Map.S with two type definitions:
type key
type !+'a t
Type 'a appears to be the type of values in the map. For example, this is the function for adding a key (of type key and value of type 'a:
val add: key -> 'a -> 'a t -> 'a t
One can write the key type like this:
module type M = Map.S with type key = string
But I couldn't figure out how to specify the value type. This isn't valid syntax:
module type M = Map.S with type key = string and 'a = int
One way to look at this is that you're trying to impose monomorphism in the wrong place. The essence of Map.S is that it's polymorphic in the element type.
You can easily define a type for maps from string keys to int values:
# module M = Map.Make(String);;
. . .
# type string_int_mod = int M.t;;
type string_int_mod = int M.t
# let f (m: string_int_mod) s i = M.add s i m;;
val f : string_int_mod -> M.key -> int -> int M.t = <fun>
In many cases, the polymorphism inferred by OCaml is clearer than specifically ascribed types. At least in my opinion. The types inferred by OCaml tell you what the code is really doing and where it has degrees of freedom.
Write a function to split a list into two lists. The length of the first part is specified by the caller.
I am new to Elm so I am not sure if my reasoning is correct. I think that I need to transform the input list in an array so I am able to slice it by the provided input number. I am struggling a bit with the syntax as well. Here is my code so far:
listSplit: List a -> Int -> List(List a)
listSplit inputList nr =
let myArray = Array.fromList inputList
in Array.slice 0 nr myArray
So I am thinking to return a list containing 2 lists(first one of the specified length), but I am stuck in the syntax. How can I fix this?
Alternative implementation:
split : Int -> List a -> (List a, List a)
split i xs =
(List.take i xs, List.drop i xs)
I'll venture a simple recursive definition, since a big part of learning functional programming is understanding recursion (which foldl is just an abstraction of):
split : Int -> List a -> (List a, List a)
split splitPoint inputList =
splitHelper splitPoint inputList []
{- We use a typical trick here, where we define a helper function
that requires some additional arguments. -}
splitHelper : Int -> List a -> List a -> (List a, List a)
splitHelper splitPoint inputList leftSplitList =
case inputList of
[] ->
-- This is a base case, we end here if we ran out of elements
(List.reverse leftSplitList, [])
head :: tail ->
if splitPoint > 0 then
-- This is the recursive case
-- Note the typical trick here: we are shuffling elements
-- from the input list and putting them onto the
-- leftSplitList.
-- This will reverse the list, so we need to reverse it back
-- in the base cases
splitHelper (splitPoint - 1) tail (head :: leftSplitList)
else
-- here we got to the split point,
-- so the rest of the list is the output
(List.reverse leftSplitList, inputList)
Use List.foldl
split : Int -> List a -> (List a, List a)
split i xs =
let
f : a -> (List a, List a) -> (List a, List a)
f x (p, q) =
if List.length p >= i then
(p, q++[x])
else
(p++[x], q)
in
List.foldl f ([], []) xs
When list p reaches the desired length, append element x to the second list q.
Append element x to list p otherwise.
Normally in Elm, you use List for a sequence of values. Array is used specifically for fast indexing access.
When dealing with lists in functional programming, try to think in terms of map, filter, and fold. They should be all you need.
To return a pair of something (e.g. two lists), use tuple. Elm supports tuples of up to three elements.
Additionally, there is a function splitAt in the List.Extra package that does exactly the same thing, although it is better to roll your own for the purpose of learning.
Total Idris newbie question, sorry.
I've been taught in school there are natural numbers (N) and natural numbers with zero (N0).
In Idris, there is data type Nat which corresponds to N0 by definition.
What would change if there will be Nat defined as follows:
data Nat = One | S Nat
data Nat0 = Zero | Nat
I guess it's easier now, but is it mainly compiler implementation issue or formal one?
There must be cases where 0 doesn't make sense and I guess these are more complicated to define correctly now.
Or not?
I've seen it defined both ways, but one reason we prefer to start from zero in Idris is that it's useful for describing the size of other structures, e.g. lists or trees. Lists can have zero things in them, trees can have a height of zero, appending two zero length lists results in a zero length list.
Using your definition would be fine, just unnecessarily fiddly when using Nat to talk about properties of other structures.
In cases where zero wouldn't make sense, you could define your data type to make it impossible to have zero as an index. Here's a (contrived and untested) example where zero wouldn't make sense, trees indexed by the number of elements, with elements stored at the leaves:
data Tree : Nat -> Type -> Type where
Leaf : ty -> Tree 1 ty
Node : Tree n ty -> Tree m ty -> Tree (n + m) ty
Given these constructors, you'll never be able to make, say, a Tree 0 Int but you'll be able to make a Tree 1 Int or Tree 2 Int or Tree n Int for any n > 0 fine...
test1 : Tree 1 Int
test1 = Leaf 94
test2 : Tree 2 Int
test2 = Node test1 test1
test3 : Tree 3 Int
test3 = Node test1 test2
test0 : Tree 0 Int
test0 = ?no_chance
I'm reading http://elm-lang.org/guide/model-the-problem and want to better understand Tagged Unions in Elm. Specifically I came across this example:
type Scale = Normal | Logarithmic
type Widget
= ScatterPlot (List (Int, Int))
| LogData (List String)
| TimePlot Scale (List (Time, Int))
The way I think it's interpreted is as follows:
Scale is a type with 2 possible values: Normal or Logarithmic
Widget is a type with 3 possible values: ScatterPlot, LogData, or TimePlot
However, how do I interpret the (List (Int, Int)) part in ScatterPlot? Similarly, how do I interpret the Scale (List (Time, Int)) part in TimePlot?
List is a built-in type, taking one parameter (another type) and meaning "a list containing values of this type as its elements". So List (Int, Int) is a list of (Int, Int). So what's (Int, Int)?
In general any (a, b) is a tuple with members of type a and type b. A tuple is a bit like a record without field names, so you can only distinguish elements by their position - however unlike a list the elements can be of different types. So (Int, Int) is a tuple containing two Ints, where Int is just an integer.
Thus, List (Int, Int) is a list of tuples of two integers.
With TimePlot you've actually got two different type parameters - Scale and List (Time, Int). The latter should now make sense given the explanation of List (Int, Int) - just the tuple has Time as its first type instead of Int.
So TimePlot takes two types as parameters, and it becomes a TimePlot Scale (List (Time, Int)).
In Elm and related languages, type notation (and function application) are defined such that any expression a b c d means a with parameters b, c, and d. If c d is meant to be one parameter it is put in parentheses.
As Andreas says, think of the union 'tags' as functions - they really are, in fact they're called "type constructors". TimePlot is a function taking a Scale and a List (Time, Int) and returning a Widget. Normal is a function with no parameters which returns a Scale, and so on.
Just think about them as function signatures. So Scatterplot must be created like this
ScatterPlot [(1,1), (2,2)]
and when you pattern match this in a case statement
case widget of
ScatterPlot l -> l -- l is from type (List (Int, Int))
LogData l -> l -- l is from type (List String)
TimePlot l -> l -- l is from type Scale (List (Time, Int))
I'm having trouble understanding what exactly a comparable is in Elm. Elm seems as confused as I am.
On the REPL:
> f1 = (<)
<function> : comparable -> comparable -> Bool
So f1 accepts comparables.
> "a"
"a" : String
> f1 "a" "b"
True : Bool
So it seems String is comparable.
> f2 = (<) 1
<function> : comparable -> Bool
So f2 accepts a comparable.
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
So String is and is not comparable?
Why is the type of f2 not number -> Bool? What other comparables can f2 accept?
Normally when you see a type variable in a type in Elm, this variable is unconstrained. When you then supply something of a specific type, the variable gets replaced by that specific type:
-- says you have a function:
foo : a -> a -> a -> Int
-- then once you give an value with an actual type to foo, all occurences of `a` are replaced by that type:
value : Float
foo value : Float -> Float -> Int
comparable is a type variable with a built-in special meaning. That meaning is that it will only match against "comparable" types, like Int, String and a few others. But otherwise it should behave the same. So I think there is a little bug in the type system, given that you get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
If the bug weren't there, you would get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
Int
String
EDIT: I opened an issue for this bug
Compare any two comparable values. Comparable values include String, Char, Int, Float, Time, or a list or tuple containing comparable values. These are also the only values that work as Dict keys or Set members.
taken from the elm docs here.
In older Elm versions:
Comparable types includes numbers, characters, strings,~~
lists of comparable things, and tuples of comparable things. Note that
tuples with 7 or more elements are not comparable; why are your tuples
so big?
This means that:
[(1,"string"), (2, "another string")] : List (Int, String) -- is comparable
But having
(1, "string", True)` : (Int, String, Bool) -- or...
[(1,True), (2, False)] : List (Int, Bool ) -- are ***not comparable yet***.
This issue is discussed here
Note: Usually people encounter problems with the comparable type when they try to use a union type as a Key in a Dict.
Tags and Constructors of union types are not comparable. So the following doesn't even compile.
type SomeUnion = One | Two | Three
Dict.fromList [ (One, "one related"), (Two, "two related") ] : Dict SomeUnion String
Usually when you try to do this, there is a better approach to your data structure. But until this gets decided - an AllDict can be used.
I think this question can be related to this one. Int and String are both comparable in the sense that strings can be compared to strings and ints can be compared to ints. A function that can take any two comparables would have a signature comparable -> comparable -> ... but within any one evaluation of the function both of the comparables must be of the same type.
I believe the reason f2 is confusing above is that 1 is a number instead of a concrete type (which seems to stop the compiler from recognizing that the comparable must be of a certain type, probably should be fixed). If you were to do:
i = 4 // 2
f1 = (<) i -- type Int -> Bool
f2 = (<) "a" -- type String -> Bool
you would see it actually does collapse comparable to the correct type when it can.