I'm playing in Purescript with a representation of Graphs that uses Cofree and the Algebraic Graph approach from https://hackage.haskell.org/package/algebraic-graphs (coming from https://hackage.haskell.org/package/apart-0.1.3/docs/Data-Apart-Structures-Graph.html)
type Graph = Cofree Edges
data Edges a = Empty | Connect a | Overlay a
connect :: forall a. Graph a -> Graph a
connect g = hoistCofree step g
where
step (Empty) = Empty
step (Connect ys) = Connect ys
step (Overlay ys) = Connect ys
Unfortunately, using hoistCofree for instance above to fully connect an existing graph, leads to an EscapedSkolem error.
However, using a simpler typed hoistCofree (borrowed from https://github.com/coot/purescript-redox/blob/v7.0.1/src/Redox/Utils.purs#L27-L32):
hoistCofree'
:: forall f state
. (Functor f)
=> (f (Cofree f state) -> f (Cofree f state))
-> Cofree f state
-> Cofree f state
hoistCofree' nat cf = head cf :< nat (hoistCofree' nat <$> tail cf)
Just works.
Is there a way I can make the code work with hoistCofree instead?
Related
I have a computation where I'm inserting values into a Map and then looking them up again. I know that I never use a key before inserting it, but using (!) freely makes me nervous anyway. I'm looking for a way to get a total lookup function that doesn't return a Maybe, and which the type system prevents me from accidentally abusing.
My first thought was to make a monad transformer similar to StateT, where the state is a Map and there are special functions for inserts and lookup in the monad. The insert function returns a Receipt s k newtype, where s is a phantom index type in the style of the ST monad and k is the type of the key, and the lookup function takes a Receipt instead of a bare key. By hiding the Receipt constructor and using a quantified run function similar to runST, this should ensure that lookups only happen after inserts in the same map. (Full code is below.)
But I fear that I've reinvented a wheel, or that that there's an alternate way to get safe, total map lookups that's already in use. Is there any prior art for this problem in a public package somewhere?
{-# LANGUAGE DeriveFunctor, LambdaCase, RankNTypes #-}
module KeyedStateT (KeyedStateT, Receipt, insert, lookup, receiptToKey, runKeyedStateT)
where
import Prelude hiding (lookup)
import Control.Arrow ((&&&))
import Control.Monad (ap, (>=>))
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromJust)
newtype KeyedStateT s k v m a = KeyedStateT (Map k v -> m (a, Map k v)) deriving Functor
keyedState :: Applicative m => (Map k v -> (a, Map k v)) -> KeyedStateT s k v m a
keyedState f = KeyedStateT (pure . f)
instance Monad m => Applicative (KeyedStateT s k v m) where
pure = keyedState . (,)
(<*>) = ap
instance Monad m => Monad (KeyedStateT s k v m) where
KeyedStateT m >>= f = KeyedStateT $ m >=> uncurry ((\(KeyedStateT m') -> m') . f)
newtype Receipt s k = Receipt { receiptToKey :: k }
insert :: (Applicative m, Ord k) => k -> v -> KeyedStateT s k v m (Receipt s k)
insert k v = keyedState $ const (Receipt k) &&& Map.insert k v
lookup :: (Applicative m, Ord k) => Receipt s k -> KeyedStateT s k v m v
lookup (Receipt k) = keyedState $ (Map.! k) &&& id
runKeyedStateT :: (forall s. KeyedStateT s k v m a) -> m (a, Map k v)
runKeyedStateT (KeyedStateT m) = m Map.empty
module Main where
import Data.Functor.Identity (runIdentity)
import qualified KeyedStateT as KS
main = putStrLn . fst . runIdentity $ KS.runKeyedStateT $ do
one <- KS.insert 1 "hello"
two <- KS.insert 2 " world"
h <- KS.lookup one
w <- KS.lookup two
pure $ h ++ w
Edit: Several commenters have asked why I want to hold on to a Receipt instead of the actual value. I want to be able to use the Receipt in Sets and Maps (I didn't add the Eq and Ord instances for Receipt in my MVCE, but I have them in my project), but the values in my Map are not equatable. If I replaced Receipt with a key-value pair newtype, I'd have to implement a dishonest Eq instance for that pair that disregarded the value, and then I'd be nervous about that. The Map is there to ensure that there's only one value under consideration for any of my equatable "proxy" keys at any given time.
I suppose an alternate solution that would work just fine for me would be a monad transformer that provides a supply of Refs, where data Ref v = Ref Int v, with the monad ensuring that Refs are given out with unique Int IDs, and Eq Ref etc. only looking at the Int (and now honesty is guaranteed by the uniqueness of the Ints). I would accept pointers to such a transformer in the wild as well.
Your solution resembles the technique used by justified-containers to guarantee that keys are present in a map. But there are some differences:
justified-containers uses continuation-passing-style.
inserting a new key in justified-containers requires "recycling" existing receipts to work in the updated map. It seems that you don't need to "recyle" receipts because you never have multiple versions of the map around at the same time.
justified-containers supports key deletion. I'm not sure if your solution could be expanded to allow the same.
An expanded description of the technique used by justified-containers can be found in the functional pearl "Ghosts of departed proofs".
I am writing a form of form of transform in OCaml that takes in a function and also accepts a list to transform. I understand something is wrong with my pattern matching in terms of type-checking, as it will not compile and claims the types do not match but I am not sure what exactly is wrong with my cases.
I receive an actual declaration error underlining the name of the function when I attempt to compile.
let rec convert (fun: 'b -> 'c option) (l: 'b list) : 'c list =
begin match l with
| [] -> []
| h::tl -> if f h = Some h then h :: convert f tl
else convert f tl
end
I wrote the following test, which should pass in order to ensure the function works properly.
let test () : bool =
let f = func x -> if x > 3 then Some (x + 1) else None in
convert f [-1; 3; 4] = [5]
;; run_test "Add one" test
I am pretty confident the error is somewhere in my second pattern match.
You should provide the exact error message in the future when asking about a compilation error (as well as the position the compiler complains about).
In h :: convert f tl, convert f tl is 'c list, but h is 'b, so you can't combine them like this. Neither does f h = Some h make sense: f h is 'c option and Some h is 'b option. You probably want to match f h instead:
| h::tl -> match f h with
| Some h1 -> ...
| None -> ...
So here is my goofy sandbox to play with Applicatives in PureScript
module Main where
import Debug.Trace
data Foo a
= Foo a
instance showFoo :: (Show a) => Show (Foo a) where
show (Foo a) = "I pity da (Foo " ++ (show a) ++ ")"
instance functorFoo :: Functor Foo where
(<$>) f (Foo a) = Foo (f a)
instance applyFoo :: Apply Foo where
(<*>) (Foo a) (Foo b) = Foo (a b)
m :: Number -> Number -> Number -> Number
m x y z = x * y - z
main = trace <<< show $ m <$> Foo 14
<*> Foo 2
<*> Foo 5
The above works fine, but if I remove:
m :: Number -> Number -> Number -> Number
it does not compile
Error at pure.purs line 18, column 1:
Error in declaration m
No instance found for Prelude.Num u1150
However (+) and (-) are both of type
forall a. (Prelude.Num a) => a -> a -> a
Why can't Number be inferred?
The reality is that when learning PureScript and coming from a dynamic language (JavaScript), I run into type errors frequently. Developing skills in diagnosing and understanding these errors is challenging without a grasp of when inference can occur and when it can't. Otherwise I will have to write types every single time in order to feel confident in my code (lameness).
This is because at the moment the compiler can't infer typeclass constraints, and as you noted the arithmetic operators are all defined in the Num typeclass.
The type that would be inferred for m (if the compiler could) would be something like:
m :: forall a. (Num a) => a -> a -> a -> a
On your second point typing top level declarations is considered good style anyway, as it helps to document your code: see here for a fuller explanation.
I need a type of tree and a map on those, so I do this:
type 'a grouping =
G of ('a * 'a grouping) list
with
member g.map f =
let (G gs) = g
gs |> List.map (fun (s, g) -> f s, g.map f) |> G
But this makes me wonder:
The map member is boilerplate. In Haskell, GHC would implement fmap for me (... deriving (Functor)). I know F# doesn't have typeclasses, but is there some other way I can avoid writing map myself in F#?
Can I somehow avoid the line let (G gs) = g?
Is this whole construction somehow non-idiomatic? It looks weird to me, but maybe that's just because putting members on sum types is new to me.
I don't think there is a way to derive automatically map, however there's a way to emulate type classes in F#, your code can be written like this:
#r #"FsControl.Core.dll"
#r #"FSharpPlus.dll"
open FSharpPlus
open FsControl.Core.TypeMethods
type 'a grouping =
G of ('a * 'a grouping) list
with
// Add an instance for Functor
static member instance (_:Functor.Map, G gs, _) = fun (f:'b->'c) ->
map (fun (s, g) -> f s, map f g) gs |> G
// TEST
let a = G [(1, G [2, G[]] )]
let b = map ((+) 10) a // G [(11, G [12, G[]] )]
Note that map is really overloaded, the first application you see calls the instance for List<'a> and the second one the instance for grouping<'a>. So it behaves like fmap in Haskell.
Also note this way you can decompose G gs without creating the let (G gs) = g
Now regarding what is idiomatic I think many people would agree your solution is more F# idiomatic, but to me new idioms should also be developed in order to get more features and overcome current language limitations, that's why I consider using a library which define clear conventions also idiomatic.
Anyway I agree with #kvb in that it's slightly more idiomatic to define map into a module, in F#+ that convention is also used, so you have the generic map and the specific ModuleX.map
This isn't a homework question, by the way. It got brought up in class but my teacher couldn't think of any. Thanks.
How do you define the identity functions ? If you're only considering the syntax, there are different identity functions, which all have the correct type:
let f x = x
let f2 x = (fun y -> y) x
let f3 x = (fun y -> y) (fun y -> y) x
let f4 x = (fun y -> (fun y -> y) y) x
let f5 x = (fun y z -> z) x x
let f6 x = if false then x else x
There are even weirder functions:
let f7 x = if Random.bool() then x else x
let f8 x = if Sys.argv < 5 then x else x
If you restrict yourself to a pure subset of OCaml (which rules out f7 and f8), all the functions you can build verify an observational equation that ensures, in a sense, that what they compute is the identity : for all value f : 'a -> 'a, we have that f x = x
This equation does not depend on the specific function, it is uniquely determined by the type. There are several theorems (framed in different contexts) that formalize the informal idea that "a polymorphic function can't change a parameter of polymorphic type, only pass it around". See for example the paper of Philip Wadler, Theorems for free!.
The nice thing with those theorems is that they don't only apply to the 'a -> 'a case, which is not so interesting. You can get a theorem out of the ('a -> 'a -> bool) -> 'a list -> 'a list type of a sorting function, which says that its application commutes with the mapping of a monotonous function.
More formally, if you have any function s with such a type, then for all types u, v, functions cmp_u : u -> u -> bool, cmp_v : v -> v -> bool, f : u -> v, and list li : u list, and if cmp_u u u' implies cmp_v (f u) (f u') (f is monotonous), you have :
map f (s cmp_u li) = s cmp_v (map f li)
This is indeed true when s is exactly a sorting function, but I find it impressive to be able to prove that it is true of any function s with the same type.
Once you allow non-termination, either by diverging (looping indefinitely, as with the let rec f x = f x function given above), or by raising exceptions, of course you can have anything : you can build a function of type 'a -> 'b, and types don't mean anything anymore. Using Obj.magic : 'a -> 'b has the same effect.
There are saner ways to lose the equivalence to identity : you could work inside a non-empty environment, with predefined values accessible from the function. Consider for example the following function :
let counter = ref 0
let f x = incr counter; x
You still that the property that for all x, f x = x : if you only consider the return value, your function still behaves as the identity. But once you consider side-effects, you're not equivalent to the (side-effect-free) identity anymore : if I know counter, I can write a separating function that returns true when given this function f, and would return false for pure identity functions.
let separate g =
let before = !counter in
g ();
!counter = before + 1
If counter is hidden (for example by a module signature, or simply let f = let counter = ... in fun x -> ...), and no other function can observe it, then we again can't distinguish f and the pure identity functions. So the story is much more subtle in presence of local state.
let rec f x = f (f x)
This function never terminates, but it does have type 'a -> 'a.
If we only allow total functions, the question becomes more interesting. Without using evil tricks, it's not possible to write a total function of type 'a -> 'a, but evil tricks are fun so:
let f (x:'a):'a = Obj.magic 42
Obj.magic is an evil abomination of type 'a -> 'b which allows all kinds of shenanigans to circumvent the type system.
On second thought that one isn't total either because it will crash when used with boxed types.
So the real answer is: the identity function is the only total function of type 'a -> 'a.
Throwing an exception can also give you an 'a -> 'a type:
# let f (x:'a) : 'a = raise (Failure "aaa");;
val f : 'a -> 'a = <fun>
If you restrict yourself to a "reasonable" strongly normalizing typed λ-calculus, there is a single function of type ∀α α→α, which is the identity function. You can prove it by examining the possible normal forms of a term of this type.
Philip Wadler's 1989 article "Theorems for Free" explains how functions having polymorphic types necessarily satisfy certain theorems (e.g. a map-like function commutes with composition).
There are however some nonintuitive issues when one deals with much polymorphism. For instance, there is a standard trick for encoding inductive types and recursion with impredicative polymorphism, by representing an inductive object (e.g. a list) using its recursor function. In some cases, there are terms belonging to the type of the recursor function that are not recursor functions; there is an example in §4.3.1 of Christine Paulin's PhD thesis.