evaluating many functions at a single point using map - dictionary
I was able to make a nice picture with Elm's share-elm.com any tips for code optimization would be appreciated but I am focusing on the last two lines:
xflip : (number, number) -> (number, number)
xflip pt = ( -1*(fst pt), snd pt)
rot : (number, number) -> (number, number)
rot pt = ( -1*(snd pt), fst pt)
mul : number -> (number, number) -> (number, number)
mul a b = (a*(fst b), a*(snd b))
add : (number, number) -> (number, number) -> (number, number)
add a b = ((fst a)+(fst b), (snd a)+(snd b))
-- implementations of the symmetries of hilbert space curve
t1 : (number, number) -> (number, number)
t1 b = (add (mul 0.5 (-100,-100)) ((mul 0.5) (rot (rot(rot (xflip b))) )))
t2 : (number, number) -> (number, number)
t2 b = (add (mul 0.5 (-100,100)) ((mul 0.5) (b)))
t3 : (number, number) -> (number, number)
t3 b = (add (mul 0.5 (100,100)) ((mul 0.5) ( b)))
t4 : (number, number) -> (number, number)
t4 b = (add (mul 0.5 (100,-100)) ((mul 0.5) (rot (xflip b) )))
--
t : [(number, number)] -> [(number, number)]
t z = (map t1 z) ++ (map t2 z) ++ (map t3 z) ++ (map t4 z)
I don't know if this is the best say to define vector addition or 2D transformations, but I needed to do it somehow. Often done with vector graphics on the graphics themselves, I am working with list of points before they become Path types.
Was this the best way to iterate the rotation function rot ? I needed to rotate 90 degrees left and then right. So I rotated left 3 times:
rot (rot(rot (xflip b)))
Onto the main question, could my last two lines be streamlined:
t : [(number, number)] -> [(number, number)]
t z = (map t1 z) ++ (map t2 z) ++ (map t3 z) ++ (map t4 z)
The list of numbers are will become my Path objects and t1 through t4 are functions. I thought maybe I could iterate over these functions with map. It works in the cases I tried on Github gist: https://gist.github.com/MonsieurCactus/ef285584f1588289b477 Here's what I tried:
t : [(number, number)] -> [(number, number)]
t z = map ( \f -> (map f z)) [t1, t2, t3 ,t4]
The Elm compiler returned the error message:
[1 of 1] Compiling Main ( Main.elm )
Type error on line 49, column 7 to 46:
map (\f -> map f z) [t1,t2,t3,t4]
Expected Type: (Float)
Actual Type: _List
Type error on line 49, column 7 to 46:
map (\f -> map f z) [t1,t2,t3,t4]
Expected Type: Float
Actual Type: (Float, Float)
Maybe I should have tried writing a function [Path] -> [Path] but then I have to get the list of points and change them anyway.
Streamlining the last two lines
Your attempt at shortening the definition of t is in the right direction. But because you map over the list of functions ([t1,t2,t3,t4]), and inside the mapping function you map over the list of points z, you end up with a list of lists of points ([[(number,number)]] instead of [(number, number)]).
So you still need to concat that list of lists. You can also use concatMap instead of a loose concat and map:
t : [(number, number)] -> [(number, number)]
t z = concatMap ( \f -> (map f z)) [t1, t2, t3 ,t4]
Iterating rot
If you don't mind using Float everywhere instead of number, you can change your rot function to take a rotation to perform. Using some basic functions, you could write something like:
rot' : Float -> (Float, Float) -> (Float, Float)
rot' angle point =
let (r,th) = toPolar point
th' = th + angle
in fromPolar (r,th')
rot = rot' (degrees 90)
Related
How can I correctly return produced sequences in an F# recursive algorithm
As a tutoring exercise I implemented the Knights Tour algorithm in CS and worked fine, after trying to port it to F# I cannot go past the part where I aggregate the resulting sequences of the Knight's path to return to the caller. The code is this: let offsets = [|(-2,-1);(-2,1);(-1,-2);(-1,2);(1,-2);(1,2);(2,-1);(2,1)|]; let squareToPair sqr = (sqr % 8, sqr / 8) let pairToSquare (col, row) = row * 8 + col // Memoizing function taken from Don Syme (http://blogs.msdn.com/b/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f.aspx) let memoize f = let cache = ref Map.empty fun x -> match (!cache).TryFind(x) with | Some res -> res | None -> let res = f x cache := (!cache).Add(x,res) res let getNextMoves square = let (col, row) = squareToPair square offsets |> Seq.map (fun (colOff, rowOff) -> (col + colOff, row + rowOff)) |> Seq.filter (fun (c, r) -> c >= 0 && c < 8 && r >= 0 && r < 8) // make sure we don't include squares out of the board |> Seq.map (fun (c, r) -> pairToSquare (c, r)) let getNextMovesMemoized = memoize getNextMoves let squareToBoard square = 1L <<< square let squareToBoardMemoized = memoize squareToBoard let getValidMoves square board = getNextMovesMemoized square |> Seq.filter (fun sqr -> ((squareToBoardMemoized sqr) &&& board) = 0L) // gets all valid moves from a particular square and board state sorted by moves which have less next possible moves let getValidMovesSorted square board = getValidMoves square board |> Seq.sortBy (fun sqr -> (getValidMoves sqr board) |> Seq.length ) let nextMoves = getValidMovesSorted let sqrToBoard = squareToBoardMemoized let findPath square = let board = sqrToBoard square let rec findPathRec brd sqr sequence = seq { match brd with | -1L -> yield sequence | _ -> for m in nextMoves sqr do yield! findPathRec (brd ||| (sqrToBoard m)) m m::sequence } findPathRec board square [square] let solution = findPath ((4,4) |> pairToSquare) |> Seq.take 1 I am getting the following error: The type '(int64 -> seq<int>)' is not a type whose values can be enumerated with this syntax, i.e. is not compatible with either seq<_>, IEnumerable<_> or IEnumerable and does not have a GetEnumerator method (using external F# compiler) I could probably be misunderstanding how this work, but I would expect the results of nextMoves to be seq<_>. Is there a better way of doing this? Am I missing something? Any recommended patterns? Thanks in advance!
So the problem is that nextMoves has type val nextMoves : (int -> int64 -> seq<int>) because it is identical to getValidMovesSorted. You need to supply the board argument
nextMoves is just getValidMovesSorted which takes two arguments (square and board) - now in findPath you only provided one and I guess you wanted to write this nextMoves sqr board but then there are more issues in the rest of the code and it's really hard to figure out what you are trying to do I think you wanted to do something like this: let findPath square = let board = sqrToBoard square let rec findPathRec brd sqr (sequence : int list) = match brd with | -1L -> sequence | _ -> [ for m in nextMoves sqr board do yield! findPathRec (brd ||| (sqrToBoard m)) m (m::sequence) ] this will compile (but will result in an stack-overflow exception)
Decompression of a list in prolog
I need to decompress a list in prolog , like in the example below : decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d] ; I made this code : divide(L,X,Y):-length(X,1),append(X,Y,L). divide2(L,X,Y):-divide(L,[X|_],[Y|_]). makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result). makelist2(L,L2):-divide2(L,X,Y),makelist(X,Y,L2). decode([],[]). decode([H|T],L):-makelist2(H,H2),append(H2,L,L2),decode(T,L2). and when i call makelist2([a,3],L2). L2 = [a,a,a]. but when i call decode([[a,3],[b,1],[c,4]],L) runs continuously. What am i doing wrong ?
Another variation of the theme, using a slightly modified version of Boris' repeat/3 predicate: % True when L is a list with N repeats of X repeat([X, N], L) :- length(L, N), maplist(=(X), L). decode(Encoded, Decoded) :- maplist(repeat, Encoded, Expanded), flatten(Expanded, Decoded). If Encode = [[a,1],[b,2],[c,1],[d,3]], then in the above decode/2, the maplist/3 call will yield Expanded = [[a],[b,b],[c],[d,d,d]], and then the flatten/2 call results in Decoded = [a,b,b,c,d,d,d]. In SWI Prolog, instead of flatten/2, you can use append/2 since you only need a "flattening" at one level. EDIT: Adding a "bidirectional" version, using a little CLPFD: rle([], []). rle([X], [[1,X]]). rle([X,Y|T], [[1,X]|R]) :- X \== Y, % use dif(X, Y) here, if available rle([Y|T], R). rle([X,X|T], [[N,X]|R]) :- N #= N1 + 1, rle([X|T], [[N1,X]|R]). This will yield: | ?- rle([a,a,a,b,b], L). L = [[3,a],[2,b]] ? ; (1 ms) no | ?- rle(L, [[3,a],[2,b]]). L = [a,a,a,b,b] ? ; no | ?- rle([a,a,a,Y,Y,Z], [X, [N,b],[M,c]]). M = 1 N = 2 X = [3,a] Y = b Z = c ? a no | ?- rle([A,B,C], D). D = [[1,A],[1,B],[1,C]] ? ; C = B D = [[1,A],[2,B]] ? ; B = A D = [[2,A],[1,C]] ? ; B = A C = A D = [[3,A]] ? ; (2 ms) no | ?- rle(A, [B,C]). A = [D,E] B = [1,D] C = [1,E] ? ; A = [D,E,E] B = [1,D] C = [2,E] ? ; A = [D,E,E,E] B = [1,D] C = [3,E] ? ; ... | ?- rle(A, B). A = [] B = [] ? ; A = [C] B = [[1,C]] ? ; A = [C,D] B = [[1,C],[1,D]] ? ; ... As #mat suggests in his comment, in Prolog implementations that have dif/2, then dif(X,Y) is preferable to X \== Y above.
The problem is in the order of your append and decode in the last clause of decode. Try tracing it, or even better, trace it "by hand" to see what happens. Another approach: see this answer. So, with repeat/3 defined as: % True when L is a list with N repeats of X repeat(X, N, L) :- length(L, N), maplist(=(X), L). You can write your decode/2 as: decode([], []). decode([[X,N]|XNs], Decoded) :- decode(XNs, Decoded_rest), repeat(X, N, L), append(L, Decoded_rest, Decoded). But this is a slightly roundabout way to do it. You could define a difference-list version of repeat/3, called say repeat/4: repeat(X, N, Reps, Reps_back) :- ( succ(N0, N) -> Reps = [X|Reps0], repeat(X, N0, Reps0, Reps_back) ; Reps = Reps_back ). And then you can use a difference-list version of decode/2, decode_1/3 decode(Encoded, Decoded) :- decode_1(Encoded, Decoded, []). decode_1([], Decoded, Decoded). decode_1([[X,N]|XNs], Decoded, Decoded_back) :- repeat(X, N, Decoded, Decoded_rest), decode_1(XNs, Decoded_rest, Decoded_back). ?- decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d]. ?- decode([[a,3],[b,1],[c,0],[d,3]],L). L = [a, a, a, b, d, d, d]. ?- decode([[a,3]],L). L = [a, a, a]. ?- decode([],L). L = [].
You can deal with both direction with this code : :- use_module(library(lambda)). % code from Pascal Bourguignon packRuns([],[]). packRuns([X],[[X]]). packRuns([X|Rest],[XRun|Packed]):- run(X,Rest,XRun,RRest), packRuns(RRest,Packed). run(Var,[],[Var],[]). run(Var,[Var|LRest],[Var|VRest],RRest):- run(Var,LRest,VRest,RRest). run(Var,[Other|RRest],[Var],[Other|RRest]):- dif(Var,Other). %end code pack_1(In, Out) :- maplist(\X^Y^(X = [V|_], Y = [V, N], length(X, N), maplist(=(V), X)), In, Out). decode(In, Out) :- when((ground(In); ground(Out1)),pack_1(Out1, In)), packRuns(Out, Out1). Output : ?- decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d] . ?- decode(L, [a,b,b,c,d,d,d]). L = [[a, 1], [b, 2], [c, 1], [d, 3]] .
a compact way: decode(L,D) :- foldl(expand,L,[],D). expand([S,N],L,E) :- findall(S,between(1,N,_),T), append(L,T,E). findall/3 it's the 'old fashioned' Prolog list comprehension facility
decode is a poor name for your predicate: properly done, you predicate should be bi-directional — if you say decode( [[a,1],[b,2],[c,3]] , L ) You should get L = [a,b,b,c,c,c]. And if you say decode( L , [a,b,b,c,c,c] ) . You should get L = [[a,1],[b,2],[c,3]]. So I'd use a different name, something like run_length_encoding/2. I might also not use a list to represent individual run lengths as [a,1] is this prolog term: .(a,.(1,[]). Just use a simple term with arity 2 — myself, I like using :/2 since it's defined as an infix operator, so you can simply say a:1. Try this on for size: run_length_encoding( [] , [] ) . % the run-length encoding of the empty list is the empty list. run_length_encoding( [X|Xs] , [R|Rs] ) :- % the run-length encoding of a non-empty list is computed by rle( Xs , X:1 , T , R ) , % - run-length encoding the prefix of the list run_length_encoding( T , Rs ) % - and recursively run-length encoding the remainder . % Easy! rle( [] , C:N , [] , C:N ) . % - the run is complete when the list is exhausted. rle( [X|Xs] , C:N , [X|Xs] , C:N ) :- % - the run is complete, X \= C % - when we encounter a break . % rle( [X|Xs] , X:N , T , R ) :- % - the run continues if we haven't seen a break, so.... N1 is N+1 , % - increment the run length, rle( Xs, X:N1, T, R ) % - and recurse down. . % Easy!
In direct answer to the original question of, What am I doing wrong?... When I ran the original code, any expected use case "ran indefinitely" without yielding a result. Reading through the main predicate: decode([],[]). This says that [] is the result of decoding []. Sounds right. decode([H|T],L) :- makelist2(H,H2), append(H2,L,L2), decode(T,L2). This says that L is the result of decoding [H|T] if H2 is an expansion of H (which is what makelist2 does... perhaps - we'll go over that below), and H2 appended to this result gives another list L2 which is the decoded form of the original tail T. That doesn't sound correct. If I decode [H|T], I should (1) expand H, (2) decode T giving L2, then (3) append H to L2 giving L. So the corrected second clause is: decode([H|T], L) :- makelist2(H, H2), decode(T, L2), append(H2, L2, L). Note the argument order of append/3 and that the call occurs after the decode of the tail. As Boris pointed out previously, the incorrect order of append and the recursive decode can cause the continuous running without any output as append with more uninstantiated arguments generates a large number of unneeded possibilities before decode can succeed. But now the result is: | ?- decode([[a,3]], L). L = [a,a,a] ? ; L = [a,a,a,a] ? ; ... If you try out our other predicates by hand in the Prolog interpreter, you'll find that makelist2/2 has an issue: It produces the correct result, but also a bunch of incorrect results. Let's have a look at makelist2/2. We can try this predicate by itself and see what happens: | ?- makelist2([a,3], L). L = [a,a,a] ? ; L = [a,a,a,a] ? ; ... There's an issue: makelist2/2 should only give the first solution, but it keeps going, giving incorrect solutions. Let's look closer at makelist/2: makelist2(L,L2) :- divide2(L,X,Y), makelist(X,Y,L2). It takes a list L of the form [A,N], divides it (via divide2/3) into X = A and Y = N, then calls an auxiliary, makelist(X, Y, L2). makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result). makelist/3 is supposed to generate a list (the third argument) by replicating the first argument the number of times given in the second argument. The second, recursive clause appears to be OK, but has one important flaw: it will succeed even if the value of Y is less than or equal to 0. Therefore, even though a correct solution is found, it keeps succeeding on incorrect solutions because the base case allows the count to be =< 0: | ?- makelist(a,2,L). L = [a,a] ? ; L = [a,a,a] ? ; We can fix makelist/2 as follows: makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). Now the code will generate a correct result. We just needed to fix the second clause of decode/2, and the second clause of makelist/3. | ?- decode([[a,3],[b,4]], L). L = [a,a,a,b,b,b,b] yes The complete, original code with just these couple of corrections looks like this: divide(L, X, Y) :- length(X, 1), append(X, Y, L). divide2(L, X, Y) :- divide(L, [X|_], [Y|_]). makelist(_, N, []) :- N =< 0 . makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). makelist2(L, L2) :- divide2(L, X, Y), makelist(X, Y, L2). decode([], []). decode([H|T], L) :- makelist2(H,H2), decode(T,L2), append(H2,L2,L). Note some simple, direct improvements. The predicate, divide2(L, X, Y) takes a list L of two elements and yields each, individual element, X and Y. This predicate is unnecessary because, in Prolog, you can obtain these elements by simple unification: L = [X, Y]. You can try this right in the Prolog interpreter: | ?- L = [a,3], L = [X,Y]. L = [a,3] X = a Y = 3 yes We can then completely remove the divide/3 and divide2/3 predicates, and replace a call to divide2(L, X, Y) with L = [X,Y] and reduce makelist2/2 to: makelist2(L, L2) :- L = [X, Y], makelist(X, Y, L2). Or more simply (because we can do the unification right in the head of the clause): makelist2([X,Y], L2) :- makelist(X, Y, L2). You could just remove makelist2/2 and call makelist/2 directly from decode/2 by unifying H directly with its two elements, [X, N]. So the original code simplifies to: makelist(_, N, []) :- N =< 0 . makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). decode([], []). decode([[X,N]|T], L) :- makelist(X, N, H2), decode(T, L2), append(H2, L2, L). And makelist/3 can be performed a bit more clearly using one of the methods provided in the other answers (e.g., see Boris' repeat/3 predicate).
All substrings that are sequences of characters using functional programming
As a followup to my earlier question on finding runs of the same character in a string, I would also like to find a functional algorithm to find all substrings of length greater than 2 that are ascending or descending sequences of letters or digits (e,g,: "defgh", "34567", "XYZ", "fedcba", "NMLK", 9876", etc.) in a character string ([Char]). The only sequences that I am considering are substrings of A..Z, a..z, 0..9, and their descending counterparts. The return value should be a list of (zero-based offset, length) pairs. I am translating the "zxcvbn" password strength algorithm from JavaScript (containing imperative code) to Scala. I would like to keep my code as purely functional as possible, for all the usual reasons given for writing in the functional programming style. My code is written in Scala, but I can probably translate an algorithm in any of Clojure, F#, Haskell, or pseudocode. Example: For the string qweABCD13987 would return [(3,4),(9,3)]. I have written a rather monsterous function that I will post when I again have access to my work computer, but I am certain that a more elegant solution exists. Once again, thanks.
I guess a nice solution for this problem is really more complicated than it seems at first. I'm no Scala Pro, so my solution is surely not optimal and nice, but maybe it gives you some ideas. The basic idea is to compute the difference between two consecutive characters, afterwards it unfortunately gets a bit messy. Ask me if some of the code is unclear! object Sequences { val s = "qweABCD13987" val pairs = (s zip s.tail) toList // if s might be empty, add a check here // = List((q,w), (w,e), (e,A), (A,B), (B,C), (C,D), (D,1), (1,3), (3,9), (9,8), (8,7)) // assuming all characters are either letters or digits val diff = pairs map {case (t1, t2) => if (t1.isLetter ^ t2.isLetter) 0 else t1 - t2} // xor could also be replaced by != // = List(-6, 18, 36, -1, -1, -1, 19, -2, -6, 1, 1) /** * * #param xs A list indicating the differences between consecutive characters * #param current triple: (start index of the current sequence; * number of current elements in the sequence; * number indicating the direction i.e. -1 = downwards, 1 = upwards, 0 = doesn't matter) * #return A list of triples similar to the argument */ def sequences(xs: Seq[Int], current: (Int, Int, Int) = (0, 1, 0)): List[(Int, Int, Int)] = xs match { case Nil => current :: Nil case (1 :: ys) => if (current._3 != -1) sequences(ys, (current._1, current._2 + 1, 1)) else current :: sequences(ys, (current._1 + current._2 - 1, 2, 1)) // "recompute" the current index case (-1 :: ys) => if (current._3 != 1) sequences(ys, (current._1, current._2 + 1, -1)) else current :: sequences(ys, (current._1 + current._2 - 1, 2, -1)) case (_ :: ys) => current :: sequences(ys, (current._1 + current._2, 1, 0)) } sequences(diff) filter (_._2 > 1) map (t => (t._1, t._2)) }
It's always best to split a problem into several smaller subproblems. I wrote a solution in Haskell, which is easier for me. It uses lazy lists, but I suppose you can convert it to Scala either using streams or by making the main function tail recursive and passing the intermediate result as an argument. -- Mark all subsequences whose adjacent elements satisfy -- the given predicate. Includes subsequences of length 1. sequences :: (Eq a) => (a -> a -> Bool) -> [a] -> [(Int,Int)] sequences p [] = [] sequences p (x:xs) = seq x xs 0 0 where -- arguments: previous char, current tail sequence, -- last asc. start offset of a valid subsequence, current offset seq _ [] lastOffs curOffs = [(lastOffs, curOffs - lastOffs)] seq x (x':xs) lastOffs curOffs | p x x' -- predicate matches - we're extending current subsequence = seq x' xs lastOffs curOffs' | otherwise -- output the currently marked subsequence and start a new one = (lastOffs, curOffs - lastOffs) : seq x' xs curOffs curOffs' where curOffs' = curOffs + 1 -- Marks ascending subsequences. asc :: (Enum a, Eq a) => [a] -> [(Int,Int)] asc = sequences (\x y -> succ x == y) -- Marks descending subsequences. desc :: (Enum a, Eq a) => [a] -> [(Int,Int)] desc = sequences (\x y -> pred x == y) -- Returns True for subsequences of length at least 2. validRange :: (Int, Int) -> Bool validRange (offs, len) = len >= 2 -- Find all both ascending and descending subsequences of the -- proper length. combined :: (Enum a, Eq a) => [a] -> [(Int,Int)] combined xs = filter validRange (asc xs) ++ filter validRange (desc xs) -- test: main = print $ combined "qweABCD13987"
Here is my approximation in Clojure: We can transform the input string so we can apply your previous algorithm to find a solution. The alorithm wont be the most performant but I think you will have a more abstracted and readable code. The example string can be transformed in the following way: user => (find-serials "qweABCD13987") (0 1 2 # # # # 7 8 # # #) Reusing the previous function "find-runs": user => (find-runs (find-serials "qweABCD13987")) ([3 4] [9 3]) The final code will look like this: (defn find-runs [s] (let [ls (map count (partition-by identity s))] (filter #(>= (% 1) 3) (map vector (reductions + 0 ls) ls)))) (def pad "#") (defn inc-or-dec? [a b] (= (Math/abs (- (int a) (int b))) 1 )) (defn serial? [a b c] (or (inc-or-dec? a b) (inc-or-dec? b c))) (defn find-serials [s] (map-indexed (fn [x [a b c]] (if (serial? a b c) pad x)) (partition 3 1 (concat pad s pad)))) find-serials creates a 3 cell sliding window and applies serial? to detect the cells that are the beginning/middle/end of a sequence. The string is conveniently padded so the window is always centered over the original characters.
polynomial equation standard ml
I'm trying to make a function that will solve a univariante polynomial equation in Standard ML, but it keeps giving me error. The code is below (* Eval Function *) - fun eval (x::xs, a:real):real = let val v = x (* The first element, since its not multiplied by anything *) val count = 1 (* We start counting from the second element *) in v + elms(xs, a, count) end; (* Helper Function*) - fun pow (base:real, 0) = 1.0 | pow (base:real, exp:int):real = base * pow(base, exp - 1); (* A function that solves the equation except the last element in the equation, the constant *) - fun elms (l:real list, a:real, count:int):real = if (length l) = count then 0.0 else ((hd l) * pow(a, count)) + elms((tl l), a, count + 1); now the input should be the coefficient if the polynomial elements and a number to substitute the variable, ie if we have the function 3x^2 + 5x + 1, and we want to substitute x by 2, then we would call the eval as follows: eval ([1.0, 5.0, 3.0], 2.0); and the result should be 23.0, but sometimes on different input, its giving me different answers, but on this imput its giving me the following error uncaught exception Empty raised at: smlnj/init/pervasive.sml:209.19-209.24 what could be my problem here?
Empty is raised when you run hd or tl on an empty list. hd and tl are almost never used in ML; lists are almost always deconstructed using pattern matching instead; it's much prettier and safer. You don't seem to have a case for empty lists, and I didn't go through your code to figure out what you did, but you should be able to work it out yourself.
After some recursive calls, elms function gets empty list as its argument. Since count is always greater than 0, (length l) = count is always false and the calls hd and tl on empty list are failed right after that. A good way to fix it is using pattern matching to handle empty lists on both eval and elms: fun elms ([], _, _) = 0.0 | elms (x::xs, a, count) = (x * pow(a, count)) + elms(xs, a, count + 1) fun eval ([], _) = 0.0 | eval (x::xs, a) = x + elms(xs, a, 1)
Deriving type expression in ML
All, I want to derive the type expression for the function below in ML: fun f x y z = y (x z) Now I know typing the same would generate the type expression. But I wish to derive these values by hand. Also, please mention the general steps to follow when deriving type expressions.
I'm going to try to do this in the most mechanical way possible, exactly as the implementation in most compilers would. Let's break it down: fun f x y z = y (x z) This is basically sugar for: val f = fn x => fn y => fn z => y (x z) Let's add some meta-syntactic type variables (these are not real SML-types, just place holders for this example's sake): val f : TX = fn (x : T2) => fn (y : T3) => fn (z : T4) => y (x z) : T5 OK, so we can start generating a system of constraints from this. T5 is the eventual return type of f. For the moment, we're going to just call the eventual type of this whole function "TX" - some fresh, unknown type variable. So the thing that is going to be generating constraints in the example you've given is function application. It tells us about the types of things in the expression. In fact, it's the only information we have! So what do the applications tell us? Ignoring the type variables we assigned above, let's just look at the body of the function: y (x z) z is not applied to anything, so we're going to just look up what the type variable we assigned to it was earlier (T4) and use that as its type. x is applied to z, but we don't know its return type yet, so let's generate a fresh type variable for that and use the type we assigned x (T2) earlier to create a constraint: T2 = T4 -> T7 y is applied to the result of (x z), which we just called T7. Once again, we don't know the return type of y yet, so we'll just give it a fresh variable: T3 = T7 -> T8 We also know that the return type of y is the return type for the whole body of the function, we we called "T5" earlier, so we add the constraint: T5 = T8 For compactness, I'm going to kludge this a little and add a constraint for TX based on the fact that there are functions being returned by functions. This is derivable by exactly the same method, except it's a little more complex. Hopefully you can do this yourself as an exercise if you're not convinced that we would eventually end up with this constraint: TX = T2 -> T3 -> T4 -> T5 Now we collect all the constraints: val f : TX = fn (x : T2) => fn (y : T3) => fn (z : T4) => y (x z) : T5 TX = T2 -> T3 -> T4 -> T5 T2 = T4 -> T7 T3 = T7 -> T8 T5 = T8 We start to solve this system of equations by substituting left hand sides with right hand sides in the system of constraints, as well as in the original expression, starting from the last constraint and working our way to the top. val f : TX = fn (x : T2) => fn (y : T3) => fn (z : T4) => y (x z) : T8 TX = T2 -> T3 -> T4 -> T8 T2 = T4 -> T7 T3 = T7 -> T8 val f : TX = fn (x : T2) => fn (y : T7 -> T8) => fn (z : T4) => y (x z) : T8 TX = T2 -> (T7 -> T8) -> T4 -> T8 T2 = T4 -> T7 val f : TX = fn (x : T4 -> T7) => fn (y : T7 -> T8) => fn (z : T4) => y (x z) : T8 TX = (T4 -> T7) -> (T7 -> T8) -> T4 -> T8 val f : (T4 -> T7) -> (T7 -> T8) -> T4 -> T8 = fn (x : T4 -> T7) => fn (y : T7 -> T8) => fn (z : T4) => y (x z) : T8 OK, so this looks horrible at the moment. We don't really need the whole body of the expression sitting around at the moment - it was just there to provide some clarity in the explanation. Basically in the symbol table we would have something like this: val f : (T4 -> T7) -> (T7 -> T8) -> T4 -> T8 The last step is to generalise all the type variables that are left over into the more familiar polymorphic types that we know and love. Basically this is just a pass, replacing the first unbound type variable with 'a, the second with 'b and so on. val f : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c Which I'm pretty sure you'll find is the type that your SML compiler will suggest for that term too. I did this by hand and from memory, so apologies if I've botched something somewhere :p I found it difficult to find a good explanation of this inference and type constraint process. I used two books to learn it - 'Modern Compiler Implementation in ML' by Andrew Appel, and 'Types and Programming Languages' by Pierce. Neither one was independently completely illuminating for me, but between the two of them I figured it out.
To determine the type of something you need to look at every place where it is used. For example if you see val h = hd l, you know that l is a list (because hd takes a list as an argument) and you also know that the type of h is the type that l is a list of. So let's say the type of h is a and the type of l is a list (where a is a placeholder). Now if you see val h2 = h*2, you know that h and h2 are ints, because 2 is an int, you can multiply an int with another int and the result of multiplying two ints is an int. Since we previously said the type of h is a this means that a is int, so the type of l is int list. So let's tackle your function: Let's consider the expressions in the order in which they are evaluated: First you do x z, i.e. you apply x to z. That means x is a function, so it has the type a -> b. Since z is given as an argument to the function it has to have the type a. The type of x z is therefor b because that is the result type of x. Now y is called with the result of x z. This means y is also a function and its argument type is the result type of x, which is b. So y has the type b -> c. Again the type of the expression y (x z) is therefor c because that is the result type of y. Since those are all the expressions in the function, we cannot restrict the types any further and therefor the most general types for x, y and z are 'a -> 'b, 'b -> 'c and 'a respectively and the type of the whole expression is 'c. This means the overall type of f is ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c For an explanation of how types are inferred programatically read about Hindley–Milner type inference.
Another way to explain type inference is that every (sub)-expression and every (sub)-pattern are assigned a type variable. Then, each construct in the program has an equation relating those type variables that are relevant to that construct. E.g., if the program contains f x and 'a1 is the type variable for the f, and 'a2 the type variable for the x, and 'a3 is the type variable for "f x", then the application results in the type equation: 'a1 = 'a2 -> 'a3 Then, type inference basically involves solving the set of type equations for a declaration. For ML this is done just by using unification, and it's pretty easy to do by hand.