I'm making a calculator on abstract integers and I'm doing an awful lot of pattern matching. I can write
add Zero x = x
add (P x) y = next $ add (prev $ P x) y
add (N x) y = prev $ add (next $ N x) y
or
add Zero x = x
add x y = case x of
P _ -> next $ add (prev x) y
_ -> prev $ add (next x) y
While the first way is shorter, something in the second way appeals to me more.
Which is the preferred way to do this?
Use as-patterns.
add Zero y = y
add x#(P _) y = next $ add (prev x) y
add x#(N _) y = prev $ add (next x) y
I'd also consider abstracting out the common structure of your two recursive branches by noting that you just swap the roles of the prev and next functions depending on whether x is positive or negative:
add Zero x = x
add x y = f $ add (g x) y
where (f, g) = case x of
P _ -> (next, prev)
N _ -> (prev, next)
About this style:
add Zero x = x
add x y = case x of
P _ -> next $ add (prev x) y
_ -> prev $ add (next x) y
On the positive side, it avoids some repetition, which is good.
On the negative side, the case looks to be non-exhaustive at a first sight. Indeed, to convince oneself that the pattern match is really exhaustive, we have to reason about the possible values for the x in case x of, and see that at runtime that can not be Zero, because that was handled above. This requires far more mental effort than the first snippet, which is obviously exhaustive.
Worse, when turning on warnings, as we should always do, GHC complains since it is not convinced that the case is exhaustive.
Personally, I wish the designers of Haskell had forbidden non exhaustive matches entirely. I'd use a -Werror-on-non-exhaustive-matches if there were one. I would like to be forced to write e.g.
case something of
A -> ...
B -> ...
_ -> error "the impossible happened"
than having the last branch being silently inserted by the compiler for me.
Consider using the math-style definition of integers as congruence classes of pairs of naturals under the equivalence relation:
{((a,b), (c,d)) | b+c == d+a}
The intuition is that the pair of naturals (a,b) represents b-a. As mentioned in the Wikipedia article, this often reduces the number of special cases compared to the "0/positive/negative" definition. In particular, the addition operation you ask about implementing becomes a one-liner:
-- both Int and Integer are taken
data Int' = Int Nat Nat
instance Num Int' where
-- b-a + d-c = (b+d)-(a+c)
Int a b + Int c d = Int (a + c) (b + d)
It's kind of fun to work through the different operations with this representation. For example, Eq can be implemented with the equation given above, and Ord is similar:
instance Eq Int' where
-- b-a == d-c = b+c == d+a
Int a b == Int c d = b+c == d+a
instance Ord Int' where
-- compare (b-a) (d-c) = compare (b+c) (d+a)
compare (Int a b) (Int c d) = compare (b+c) (d+a)
On occasion, it can be handy to normalize these things. Just like fractions can be reduced by multiplying the numerator and denominator by the same number until they're relatively prime, these things can be reduced by adding or subtracting the same number to both parts until (at least) one of them is zero.
normalize (Int (S a) (S b)) = normalize (Int a b)
normalize v = v
Related
I want to add two positive numbers together without the use of any basic operators like + for addition. I've already worked my way around that (in the add''' function) (i think) may not be efficient but thats not the point right now. I am getting lots of type errors however which i have no idea how to handle, and is very confusing for me as it works on paper and i've come from python.
add 1245 7489
--add :: Int -> Int -> Int
add x y = add'' (zip (add' x) (add' y))
where
add' :: Int -> [Int]
add' 0 = []
add' x = add' (x `div` 10) ++ [x `mod` 10]
conversion [1,2,4,5] [7,4,8,9] then zipping them together [(1,7),(2,4)....]
add'' :: [(Int,Int)] -> [Int]
add'' (x:xs) = [(add''' (head x) (last x))] ++ add'' xs
summary [8,6,...] what happens when the sum reaches 10 is not implemented yet.
where
--add''' :: (Int,Int) -> Int
add''' x y = last (take (succ y) $ iterate succ x)
adding two numbers together
You can't use head and last on tuples. ...Frankly, you should never use these functions at all because they're unsafe (partial), but they can be used on lists. In Haskell, lists are something completely different from tuples.To get at the elements of a tuple, use pattern matching.
add'' ((x,y):xs) = [add''' x y] ++ add'' xs
(To get at the elements of a list, pattern matching is very often the best too.) Alternatively, you can use fst and snd, these do on 2-tuples what you apparently thought head and last would.
Be clear which functions are curried and which aren't. The way you write add''', its type signature is actually Int -> Int -> Int. That is equivalent to (Int, Int) -> Int, but it's still not the same to the type checker.
The result of add'' is [Int], but you're trying to use this as Int in the result of add. That can't work, you need to translate from digits to numbers again.
add'' doesn't handle the empty case. That's fixed easily enough, but better than doing this recursion at all is using standard combinators. In your case, this is only supposed to work element-wise anyway, so you can simply use map – or do that right in the zipping, with zipWith. Then you also don't need to unwrap any tuples at all, because it works with a curried function.
A clean version of your attempt:
add :: Int -> Int -> Int
add x y = fromDigits 0 $ zipWith addDigits (toDigits x []) (toDigits y [])
where
fromDigits :: Int -> [Int] -> Int
fromDigits acc [] = acc
fromDigits acc (d:ds)
= acc `seq` -- strict accumulator, to avoid thunking.
fromDigits (acc*10 + d) ds
toDigits :: Int -> [Int] -> [Int] -- yield difference-list,
toDigits 0 = id -- because we're consing
toDigits x = toDigits (x`div`10) . ((x`mod`10):) -- left-associatively.
addDigits :: Int -> Int -> Int
addDigits x y = last $ take (succ x) $ iterate succ y
Note that zipWith requires both numbers to have the same number of digits (as does zip).
Also, yes, I'm using + in fromDigits, making this whole thing pretty futile. In practice you would of course use binary, then it's just a bitwise-or and the multiplication is a left shift. What you actually don't need to do here is take special care with 10-overflow, but that's just because of the cheat of using + in fromDigits.
By head and last you meant fst and snd, but you don't need them at all, the components are right there:
add'' :: [(Int, Int)] -> [Int]
add'' (pair : pairs) = [(add''' pair)] ++ add'' pairs
where
add''' :: (Int, Int) -> Int
add''' (x, y) = last (take (succ y) $ iterate succ x)
= iterate succ x !! y
= [x ..] !! y -- nice idea for an exercise!
Now the big question that remains is what to do with those big scary 10-and-over numbers. Here's a thought: produce a digit and a carry with
= ([(d, 0) | d <- [x .. 9]] ++ [(d, 1) | d <- [0 ..]]) !! y
Can you take it from here? Hint: reverse order of digits is your friend!
the official answer my professor gave
works on positive and negative numbers too, but still requires the two numbers to be the same length
add 0 y = y
add x y
| x>0 = add (pred x) (succ y)
| otherwise = add (succ x) (pred y)
The other answers cover what's gone wrong in your approach. From a theoretical perspective, though, they each have some drawbacks: they either land you at [Int] and not Int, or they use (+) in the conversion back from [Int] to Int. What's more, they use mod and div as subroutines in defining addition -- which would be okay, but then to be theoretically sound you would want to make sure that you could define mod and div themselves without using addition as a subroutine!
Since you say efficiency is no concern, I propose using the usual definition of addition that mathematicians give, namely: 0 + y = y, and (x+1) + y = (x + y)+1. Here you should read +1 as a separate operation than addition, a more primitive one: the one that just increments a number. We spell it succ in Haskell (and its "inverse" is pred). With this theoretical definition in mind, the Haskell almost writes itself:
add :: Int -> Int -> Int
add 0 y = y
add x y = succ (add (pred x) y)
So: compared to other answers, we can take an Int and return an Int, and the only subroutines we use are ones that "feel" more primitive: succ, pred, and checking whether a number is zero or nonzero. (And we land at only three short lines of code... about a third as long as the shortest proposed alternative.) Of course the price we pay is very bad performance... try add (2^32) 0!
Like the other answers, this only works for positive numbers. When you are ready for handling negative numbers, we should chat again -- there's some fascinating mathematical tricks to pull.
Reading this answer, I'm getting puzzled by the very first code fragment:
data Pair a = P a a
instance Functor Pair where
fmap f (P x y) = P (f x) (f y)
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
What I see is the author redefining a data constructor two times and applying it to undefined variables.
First off, how does the second of the two definitions of P (those two that are found in the where clause of the instance Monad definition) matter if, as I believe, the first one (whichever we put first) always matches?
Second, according to what syntax rules could the expression P x y get evaluated when there are no expressions for x and y in scope, but rather some kind of a redefinition of a data constructor that happens to mention these variables' names?
Interesting to note that, if I instead write like:
P a b >>= f = P x y
where P u _ = f a
P _ v = f b
— substituting u & v for x & y
— I will observe an error: Variable not in scope for each of x & y, even though by all sane intuition renaming a bound variable makes no difference.
The equation
P x y = z
does not define P, only x and y. This is the case in general: only the data and newtype keywords can introduce new constructors. All other equations define only term variables. To disambiguate between the two, constructors always begin with upper case (for the special case of operators, : counts as "upper case punctuation") and variables always begin with lower case.
So, the meaning of
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
reads like this:
Define a new function named (>>=). It is defined when the first argument matches the pattern P a b (binding a and b to the actual values P is applied to in the first argument), and when the second argument matches the pattern f (that is, always, and binding f to the value of that second argument).
Apply f to a. Make sure the result of this matches the pattern P x _ (binding x to the first value P is applied to and throwing away the second).
Apply f to b. Make sure the result of this matches the pattern P _ y (binding y to the second value P is applied to and throwing away the first).
Return the value P x y.
How can I write a type declaration and function in Haskell that takes either a function (that itself takes no arguments) or a value. When given a function it calls the function. When given a value it returns the value.
[edit] To give more context, I'm mostly curious how to solve this problem in Haskell without bit twiddling: Designing function f(f(n)) == -n
Sean
I'm mostly curious how to solve this problem in Haskell without bit twiddling: Designing function f(f(n)) == -n
That's actually quite easy to solve:
when :: (a -> Bool) -> (a -> a) -> a -> a
when p f x = if p x then f x else x
f :: Integer -> Integer
f = (+) <$> when even negate <*> signum
How do we derive this? Consider:
f (f n) = (-n) -- (0) - from the interview question
f x = y -- (1) - assumption
f y = (-x) -- (2) - from (0) and (1), f (f x) = (-x)
f (-x) = (-y) -- (3) - from (0) and (2), f (f y) = (-y)
f (-y) = x -- (4) - from (0) and (3), f (f (-x)) = x
Now, if you see the left hand sides of these equations then you'll notice that there are four cases:
f x.
f y.
f (-x).
f (-y).
Notice that the domain of the function f is divided into positive and negative numbers, x and (-x), and y and (-y). Let's assume that x and y together form the set of positive numbers and (-x) and (-y) together form the set of negative numbers.
The set of positive numbers is divided into two proper disjoint subsets, x and y. How do we divide the set of positive numbers into two proper disjoint subsets? Odd and even numbers are a good candidate. Hence, let's assume that x is the set of positive odd numbers and y is the set of positive even numbers.
Another advantage of using odd and even numbers is that when negated odd numbers remain odd and even numbers remain even. Hence, (-x) is the set of negative odd numbers and (-y) is the set of negative even numbers.
Now, consider the four cases again. Notice that the sign only changes when the number is even:
f x = y (sign does not change).
f y = (-x) (sign changes).
f (-x) = (-y) (sign does not change).
f (-y) = x (sign changes).
Hence, we only negate the number when it is even (i.e. when even negate).
Next, we need to convert odd numbers into even numbers and vice versa. The easiest way to do so is to add or subtract one from the number. However, care should be taken that the resulting number is not 0. Consider the special case of 0:
f 0 = z -- (a) - assumption
f z = (-0) -- (b) - from (0) and (a), f (f 0) = (-0)
f (-0) = (-z) -- (c) - from (0) and (b), f (f z) = (-z)
(-0) = 0 -- (d) - reflexivity
f (-0) = f 0 -- (e) - from (d)
(-z) = z -- (f) - from (a) and (c) and (e)
z = 0 -- (g) - from (d) and (f)
f 0 = 0 -- (h) - from (a) and (g)
Hence, f n = 0 if and only if n = 0. So let's consider the neighbors of 0, 1 and (-1). Both of them are odd numbers. Hence, they are not negated. However, they do need to be converted into an even number (except for 0). Hence, 1 is converted into 2 and (-1) is converted into (-2).
Thus, for odd numbers we simply add the sign of the number to the number itself.
Now, consider even numbers. We know:
f 1 = 2 -- (A)
f (-1) = (-2) -- (B)
Therefore:
f 2 = (-1) -- (C), from (0) and (A), f (f 1) = (-1)
f (-2) = 1 -- (D), from (0) and (B), f (f (-1)) = 1
We know that even numbers are always negated. Hence, 2 first becomes (-2) and vice versa. Let the original even number be n. Hence, first we negate n and then add signum n to it:
evenF n = negate n + signum n
evenF 2 = negate 2 + signum 2
= (-2) + 1
= (-1)
evenF (-2) = negate (-2) + signum (-2)
= 2 + (-1)
= 1
evenF 0 = negate 0 + signum 0
= 0 + 0
= 0
Thus, for both the odd case and the even case we add the sign of the original number to when even negate. Therefore, f is defined as:
f :: Integer -> Integer
f = (+) <$> when even negate <*> signum
Hope that helps.
You can't write a function with two different signatures (unless you use typeclasses, but typeclasses are not suitable for this problem). You must solve this in a way that lets you treat both functions and non-function values as the same type. There are two obvious options:
Use a sum type.
f :: Either (Int -> Char) Char -> Char
f (Left g) = g 1
f (Right c) = c
Use const to convert your non-function value into a function that ignores its argument:
f = ($ 42)
f chr --> '*'
f (const 'a') --> 'a'
However, since this is a very unHaskelly thing to ask for, I suspect that this is an XY problem.
You could do it like this:
data FunctionOrValue a
= Function (() -> a)
| Value a
getValue :: FunctionOrValue a -> a
getValue (Function f) = f ()
getValue (Value x) = x
However this is a bit silly.
It sounds like you're trying to defer values manually, but since Haskell is lazy, there's not normally a need to do this.
An answer based on the interview question you posted:
f n = if (abs fracN) > 1 then 1/fracN else - (1/fracN)
where
fracN = realToFrac n
The question specified that the input is an int; it did not specify that the result must also be an int.
Edit: if you must return an Int, note that the question allows you to specify a range of possible inputs. I use a limit of 1073741823 (half of the max value of a signed 32-bit int), which allows me to write this:
fint :: Int -> Int
fint 0 = 0
fint n = if (abs n) <= rangeVal then n+addend else -(n-addend)
where
rangeVal = 1073741823
negator = if n < 0 then -1 else 1
addend = negator*rangeVal
One of the nice thing in Haskell (IMHO) is there is no difference between a value and a function without parameter returning a value (thanks to lazyness AND purity). Or if you prefer, every value is in fact a function without parameter which will be evaluated when needed. Therefore there is no need to worry about that type of problem. There is no such thing like f(), it's just f.
For example, you can write
x = 3 :: Int
f = head [] :: Int -- should blow up but doesn't
head [x, f] -- note that f and x have the same type
> 3 -- doesn't blow up on f, because f is not called
head [f] -- blows up, when trying to print f
I recently learned about Data.Function.fix, and now I want to apply it everywhere. For example, whenever I see a recursive function I want to "fix" it. So basically my question is where and when should I use it.
To make it more specific:
1) Suppose I have the following code for factorization of n:
f n = f' n primes
where
f' n (p:ps) = ...
-- if p^2<=n: returns (p,k):f' (n `div` p^k) ps for k = maximum power of p in n
-- if n<=1: returns []
-- otherwise: returns [(n,1)]
If I rewrite it in terms of fix, will I gain something? Lose something? Is it possible, that by rewriting an explicit recursion into fix-version I will resolve or vice versa create a stack overflow?
2) When dealing with lists, there are several solutions: recursion/fix, foldr/foldl/foldl', and probably something else. Is there any general guide/advice on when to use each? For example, would you rewrite the above code using foldr over the infinite list of primes?
There are, probably, other important questions not covered here. Any additional comments related to the usage of fix are welcome as well.
One thing that can be gained by writing in an explicitly fixed form is that the recursion is left "open".
factOpen :: (Integer -> Integer) -> Integer -> Integer
factOpen recur 0 = 1
factOpen recur n = n * recur (pred n)
We can use fix to get regular fact back
fact :: Integer -> Integer
fact = fix factOpen
This works because fix effectively passes a function itself as its first argument. By leaving the recursion open, however, we can modify which function gets "passed back". The best example of using this property is to use something like memoFix from the memoize package.
factM :: Integer -> Integer
factM = memoFix factOpen
And now factM has built-in memoization.
Effectively, we have that open-style recursion requires us impute the recursive bit as a first-order thing. Recursive bindings are one way that Haskell allows for recursion at the language level, but we can build other, more specialized forms.
I'd like to mention another usage of fix; suppose you have a simple language consisting of addition, negative, and integer literals. Perhaps you have written a parser which takes a String and outputs a Tree:
data Tree = Leaf String | Node String [Tree]
parse :: String -> Tree
-- parse "-(1+2)" == Node "Neg" [Node "Add" [Node "Lit" [Leaf "1"], Node "Lit" [Leaf "2"]]]
Now you would like to evaluate your tree to a single integer:
fromTree (Node "Lit" [Leaf n]) = case reads n of {[(x,"")] -> Just x; _ -> Nothing}
fromTree (Node "Neg" [e]) = liftM negate (fromTree e)
fromTree (Node "Add" [e1,e2]) = liftM2 (+) (fromTree e1) (fromTree e2)
Suppose someone else decides to extend the language; they want to add multiplication. They will have to have access to the original source code. They could try the following:
fromTree' (Node "Mul" [e1, e2]) = ...
fromTree' e = fromTree e
But then Mul can only appear once, at the top level of the expression, since the call to fromTree will not be aware of the Node "Mul" case. Tree "Neg" [Tree "Mul" a b] will not work, since the original fromTree has no pattern for "Mul". However, if the same function is written using fix:
fromTreeExt :: (Tree -> Maybe Int) -> (Tree -> Maybe Int)
fromTreeExt self (Node "Neg" [e]) = liftM negate (self e)
fromTreeExt .... -- other cases
fromTree = fix fromTreeExt
Then extending the language is possible:
fromTreeExt' self (Node "Mul" [e1, e2]) = ...
fromTreeExt' self e = fromTreeExt self e
fromTree' = fix fromTreeExt'
Now, the extended fromTree' will evaluate the tree properly, since self in fromTreeExt' refers to the entire function, including the "Mul" case.
This approach is used here (the above example is a closely adapted version of the usage in the paper).
Beware the difference between _Y f = f (_Y f) (recursion, value--copying) and fix f = x where x = f x (corecursion, reference--sharing).
Haskell's let and where bindings are recursive: same name on the LHS and RHS refer to the same entity. The reference is shared.
In the definition of _Y there's no sharing (unless a compiler performs an aggressive optimization of common subexpressions elimination). This means it describes recursion, where repetition is achieved by application of a copy of an original, like in a classic metaphor of a recursive function creating its own copies. Corecursion, on the other hand, relies on sharing, on referring to same entity.
An example, primes calculated by
2 : _Y ((3:) . gaps 5 . _U . map (\p-> [p*p, p*p+2*p..]))
-- gaps 5 == ([5,7..] \\)
-- _U == sort . concat
either reusing its own output (with fix, let g = ((3:)...) ; ps = g ps in 2 : ps) or creating separate primes supply for itself (with _Y, let g () = ((3:)...) (g ()) in 2 : g ()).
See also:
double stream feed to prevent unneeded memoization?
How to implement an efficient infinite generator of prime numbers in Python?
Or, with the usual example of factorial function,
gen rec n = n<2 -> 1 ; n * rec (n-1) -- "if" notation
facrec = _Y gen
facrec 4 = gen (_Y gen) 4
= let {rec=_Y gen} in (\n-> ...) 4
= let {rec=_Y gen} in (4<2 -> 1 ; 4*rec 3)
= 4*_Y gen 3
= 4*gen (_Y gen) 3
= 4*let {rec2=_Y gen} in (3<2 -> 1 ; 3*rec2 2)
= 4*3*_Y gen 2 -- (_Y gen) recalculated
.....
fac = fix gen
fac 4 = (let f = gen f in f) 4
= (let f = (let {rec=f} in (\n-> ...)) in f) 4
= let {rec=f} in (4<2 -> 1 ; 4*rec 3) -- f binding is created
= 4*f 3
= 4*let {rec=f} in (3<2 -> 1 ; 3*rec 2)
= 4*3*f 2 -- f binding is reused
.....
1) fix is just a function, it improves your code when you use some recursion. It makes your code prettier.For example usage visit: Haskell Wikibook - Fix and recursion.
2) You know what does foldr? Seems like foldr isn't useful in factorization (or i didn't understand what are you mean in that).
Here is a prime factorization without fix:
fact xs = map (\x->takeWhile (\y->y/=[]) x) . map (\x->factIt x) $ xs
where factIt n = map (\x->getFact x n []) [2..n]
getFact i n xs
| n `mod` i == 0 = getFact i (div n i) xs++[i]
| otherwise = xs
and with fix(this exactly works like the previous):
fact xs = map (\x->takeWhile (\y->y/=[]) x) . map (\x->getfact x) $ xs
where getfact n = map (\x->defact x n) [2..n]
defact i n =
fix (\rec j k xs->if(mod k j == 0)then (rec j (div k j) xs++[j]) else xs ) i n []
This isn't pretty because in this case fix isn't a good choice(but there is always somebody who can write it better).
The fixed point combinator doesn't always produce the right answer given the definition:
fix f = f (fix f)
The following code does not terminate:
fix (\x->x*x) 0
Of course, fix can't always produce the right answer, but I was wondering, can this be improved?
Certainly for the above example, one can implement some fix that looks like
fix f x | f x == f (f x) = f x
| otherwise = fix f (f x)
and gives the correct output.
What is the reason the above definition (or something even better, as this one only handle function with 1 parameter) is not used instead?
Fixed point combinator finds the least-defined fixed point of a function, which is ⊥ in your case (non-termination indeed is undefined value).
You can check, that in your case
(\x -> x * x) ⊥ = ⊥
i.e. ⊥ really is fixed point of \x -> x * x.
As for why is fix defined that way: the main point of fix is to allow you use anonymous recursion and for that you do not need more sophisticated definition.
Your example does not even typecheck:
Prelude> fix (\x->x*x) 0
<interactive>:1:11:
No instance for (Num (a0 -> t0))
arising from a use of `*'
Possible fix: add an instance declaration for (Num (a0 -> t0))
In the expression: x * x
In the first argument of `fix', namely `(\ x -> x * x)'
In the expression: fix (\ x -> x * x) 0
And that gives the clue as to why it doesn't work as you expect. The x in your anonymous function is supposed to be a function, not a number. The reason for this is, as Vitus suggests, that a fixpoint combinator is a way to write recursion without actually writing recursion. The general idea is that a recursive definition like
f x = if x == 0 then 1 else x * f (x-1)
can be written as
f = fix (\f' x -> if x == 0 then 1 else x * f' (x-1))
Your example
fix (\x->x*x) 0
thus corresponds to the expression
let x = x*x in x 0
which makes no sense.
I'm not entirely qualified to talk about what the "fixpoint combinator" is, or what the "least fixed point" is, but it is possible to use a fix-esque technique to approximate certain functions.
Translating Scala by Example section 4.4 to Haskell:
sqrt' :: Double -> Double
sqrt' x = sqrtIter 1.0
where sqrtIter guess | isGoodEnough guess = guess
| otherwise = sqrtIter (improve guess)
improve guess = (guess + x / guess) / 2
isGoodEnough guess = abs (guess * guess - x) < 0.001
This function works by repeatedly "improving" a guess until we determine that it is "good enough". This pattern can be abstracted:
myFix :: (a -> a) -- "improve" the guess
-> (a -> Bool) -- determine if a guess is "good enough"
-> a -- starting guess
-> a
fixApprox improve isGoodEnough startGuess = iter startGuess
where iter guess | isGoodEnough guess = guess
| otherwise = iter (improve guess)
sqrt'' :: Double -> Double
sqrt'' x = myFix improve isGoodEnough 1.0
where improve guess = (guess + x / guess) / 2
isGoodEnough guess = abs (guess * guess - x) < 0.001
See also Scala by Example section 5.3. fixApprox can be used to approximate the fixed point of the improve function passed into it. It repeatedly invokes improve on the input until the output isGoodEnough.
In fact, you can use myFix not only for approximations, but for exact answers as well.
primeAfter :: Int -> Int
primeAfter n = myFix improve isPrime (succ n)
where improve = succ
isPrime x = null [z | z <- [2..pred x], x `rem` z == 0]
This is a pretty dumb way to generate primes, but it illustrates the point. Hm...now I wonder...does something like myFix already exist? Stop...Hoogle time!
Hoogling (a -> a) -> (a -> Bool) -> a -> a, the very first hit is until.
until p f yields the result of applying f until p holds.
Well there you have it. As it turns out, myFix = flip until.
You probably meant iterate:
*Main> take 8 $ iterate (^2) (0.0 ::Float)
[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
*Main> take 8 $ iterate (^2) (0.001 ::Float)
[1.0e-3,1.0000001e-6,1.0000002e-12,1.0000004e-24,0.0,0.0,0.0,0.0]
*Main> take 8 $ iterate (^2) (0.999 ::Float)
[0.999,0.99800104,0.9960061,0.9920281,0.9841198,0.96849173,0.93797624,0.8797994]
*Main> take 8 $ iterate (^2) (1.0 ::Float)
[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]
*Main> take 8 $ iterate (^2) (1.001 ::Float)
[1.001,1.002001,1.0040061,1.0080284,1.0161213,1.0325024,1.0660613,1.1364866]
Here you have all the execution history explicitly available for your analysis. You can attempt to detect the fixed point with
fixed f from = snd . head
. until ((< 1e-16).abs.uncurry (-).head) tail
$ _S zip tail history
where history = iterate f from
_S f g x = f x (g x)
and then
*Main> fixed (^2) (0.999 :: Float)
0.0
but trying fixed (^2) (1.001 :: Float) will loop indefinitely, so you'd need to develop separate testing for convergence, and even then detection of repellent fixed points like 1.0 will need more elaborate investigation.
You can't define fix the way you've mentioned since f x may not even be comparable. For instance, consider the example below:
myFix f x | f x == f (f x) = f x
| otherwise = myFix f (f x)
addG f a b =
if a == 0 then
b
else
f (a - 1) (b + 1)
add = fix addG -- Works as expected.
-- addM = myFix addG (Compile error)