Is there theory/language where we can create a function type such that when it typechecks, the function is memory safe? - programming-languages

What is I want to achieve is, I might want to define a property called like these
MemorySafe :: Function -> Proposition
MemorySafe func = match func
| allocate => impossible!
| deallocate => impossible!
| {first_node_of_its_flow_graph, remaining_nodes} => ...
// such that we require allocated memory is also deallocated after within the function body in order to produce a proof
my_func :: ...
my_func = do
y <- allocate 128 // bytes
MemorySafe my_func // (cannot type check)
my_func2 :: ...
my_func2 = do
y <- allocate 128 // bytes
deallocate y
MemorySafe my_func // (type checks)
Of course it is much more complicated, such as with function call we need to deal with the recursive case, with variables we need to keep track of the which variables are holding which part of the memory and so on.
Do we need some kind of primitive effects (counterpart for computations of the primitive types (integer, string) for values) to be able to achieve this (so that all memory allocation comes down to some functions allocate and deallocate)?
Also, is pattern matching a function even possible?

Related

In Haskell, does mutability always have to be reflected in type system?

I'm new to Haskell, so please forgive if this question is dumb.
Imagine that we have two data structures bound to the names x and y.
x is mutable.
y is not.
As a matter or principle, does x necessarily have a different type than y?
Short answer: yes.
In Haskell, all variables are technically immutable. Unlike in, say, JavaScript, once you've defined a new variable in Haskell and bound it to an initial value:
let x = expression1 in body1
that's its value forever. Everywhere that x is used in body1, its value is guaranteed to be the (fixed) value of expression1. (Well, technically, you can define a brand new immutable variable x with the same name in body1 and then some of the xs in body might refer to that new variable, but that's a whole different matter.)
Haskell does have mutable data structures. We use them by creating a new mutable structure and binding that to an immutable variable:
do ...
xref <- newIORef (15 :: Int)
...
Here, the value of xref itself is not the integer 15. Rather, xref is assigned an immutable, undisplayable value that identifies a "container" whose contents are currently 15. To use this container, we need to explicitly pull values out of it, which we can assign to immutable variables:
value_of_x_right_now <- readIORef xref
and explicitly put values into it:
writeIORef xref (value_of_x_right_now + 15)
There's obviously much more that can be said about these values, and the way in which they generally need to be accessed via monadic operations in IO or another monad.
But, even setting that aside, it should be clear that the integer 15 and a "container whose contents are initialized to the integer 15" are objects with necessarily different types. In this case, the types are Int and IORef Int respectively.
So, the mutability of data structures will necessarily be reflected at the type level, simply by virtue of the fact that mutability in Haskell is implemented via these sorts of "containers", and the type of a value is not the same as the type of a container containing that value.

Testing for memory leak in Fortran (using pFUnit)

I've wrote my first program using allocatable. It works as expected. But, does it really? And more importantly, how can I set up a unit-test to catch memory leaks?
The idea behind the program is to allocate a chunck of storage room for my list of objects in the first place. And every time I add one more element more to the list than the allocated size, I double the allocation. I do this to reduce the number of allocations and subsequent copying of data from the old allocated memory, to the newly allocated memory.
I might over complicate this, but I'd like to spend some time now understanding the pitfalls, rather than falling head first into them a year or two down into the project.
The ode is compiled with gfortran 8.3.0 on linux. And using pFUnit 4.1. The code below is an extract to test only the allocation part.
Heres my test-program:
program test_realloc
use class_test_malloc
integer :: i
real :: x, y
type(tmalloc) :: myobject
call myobject%initialize()
do i=1, 100
x = i * i
y = sqrt(x)
call myobject%add_nbcell(i, x, y)
end do
call myobject%dump()
end program test_realloc
array_reallocation.f:
!
! Simple test to see if my understanding of dynamicly allocation
! of arrays is correct.
!
module class_test_malloc
use testinglistobj
implicit none
type tmalloc
integer :: numnbcells, maxnbcells
type(listobj), allocatable :: nbcells(:)
contains
procedure, public :: initialize => init
procedure, public :: add_nbcell ! Might be private?
procedure, private :: expand_nbcells
procedure, public :: dump
end type tmalloc
contains
subroutine init(this)
class(tmalloc), intent(inout) :: this
this%numnbcells = 0
this%maxnbcells = 4
allocate (this%nbcells(this%maxnbcells))
end subroutine init
subroutine add_nbcell(this, idx, x, y)
class(tmalloc), intent(inout) :: this
integer, intent(in) :: idx
real, intent(in) :: x, y
type(listobj) :: nbcell
if(this%numnbcells .eq. this%maxnbcells) then
call this%expand_nbcells()
print *,"Expanding"
endif
this%numnbcells = this%numnbcells + 1
nbcell%idx = idx
nbcell%x = x
nbcell%y = y
this%nbcells(this%numnbcells) = nbcell
print *,"Adding"
end subroutine add_nbcell
subroutine expand_nbcells(this)
class(tmalloc), intent(inout) :: this
type(listobj), allocatable :: tmpnbcells(:)
integer :: size
size = this%maxnbcells *2
allocate (tmpnbcells(size))
tmpnbcells(1:this%maxnbcells) = this%nbcells
call move_alloc( from=tmpnbcells, to=this%nbcells)
this%maxnbcells = size
end subroutine
subroutine dump(this)
class(tmalloc), intent(inout) :: this
integer :: i
do i=1, this%numnbcells
print*, this%nbcells(i)%x, this%nbcells(i)%y
end do
end subroutine
end module
listobj.f:
module testinglistobj
type listobj
integer :: idx
real :: x
real :: y
end type
end module testinglistobj
You will not get any memory leaks with this code. The reason is, and this is fundamental to the understanding of allocatable arrays, is that in Fortran 95 onwards it is required that allocatable arrays without the save attribute automatically get deallocated when they go out of scope. The nett result of this is that memory leaks for such arrays are impossible. This is one very good reason why you should prefer allocatable arrays to pointers. Related is the general software engineering principle of keeping the scope of variables as limited as possible, so that arrays are in memory for as short a period as possible.
Note this does not mean that you should never deallocate them as an array may remain in scope long after it is actually useful. Here "manual" deallocation may be of use. But it is not a memory leak.

Stop and copy garbage collector in OCAML

I have a homework assignment to finish writing a stopy-and-copy garbage collector in OCaml. There are 3 functions that need to be written. The first thing to be known is that a 64 slot array named ram will be what the garbage collector uses as memory. Each slot will contain an object of type 'cell'. That type may look like the following:
Object (id, size, references)
ObjData _
Free
FwdPointer (_)
I believe I am okay with the first function but the second function I need help with.
The function is:
let rec scan_tospace (free : int) (unscanned : int) =
Here is the objective of the function:
(* Scan To-space, copy all referenced objects to the To-space and
update references in objects. Recurse until the free pointer is
identical to the unscanned pointer.
[free] is the pointer to the next free address in the To-space,
[unscanned] is the address of the first unscanned object in the
To-space.
Return the address of the free pointer after all objects have been
scanned.
*)
What I want to do is pattern matching on the element at the unscanned pointer. If it is an object (x,y,z) then I want the result to go through each element in the integer list z and apply the function 'let copy_obj (free : int) (addr : int) =' to it as the argument addr. The problem is that the function copy_obj takes 2 arguments and I can't figure out how to also insert the second argument when calling List.iter like so:
List.iter obj_copy free z
I've also tried this as the result when it successfully matches with an object:
List.iter (fun k -> match k with
| int k -> copy_obj free k) z;
There I get this:
Error: This expression has type int * int
but an expression was expected of type unit
I didn't post any code on purpose, but if you'd liked see it I can post more. I didn't want to give any answers away. Also, I'm not look for someone to write any code for me, another reason I didn't post much of it. Any ideas in the right direction would be very helpful, thanks!
List.iter obj_copy free z should be List.iter (obj_copy free) z so the free is the first argument to obj_copy and the items in the list are the second. With this change you should get the same error as your later code.
The problem here is the use of List.iter. As you go over the referenced objects and copy them free has to change. Otherwise you copy each object over the previous one. You also need to remember where the copied objects now are so you can update the references in the outer object. Accordingly copy_obj returns (I assume) a tuple of the object and the new free.
You have to use List.fold_left or List.fold_right or manual recursion to go through the list while keeping track of free and the copied objects.

Does Data.Map work in a pass-by-value or pass-by-reference way? (Better explanation inside)

I have a recursive function working within the scope of strictly defined interface, so I can't change the function signatures.
The code compiles fine, and even runs fines without error. My problem is that it's a large result set, so it's very hard to test if there is a semantic error.
My primary question is: In a sequence of function calls A to B to A to B to breaking condition, considering the same original Map is passed to all functions until breaking condition, and that some functions only return an Integer, would an insert on a Map in a function that only returns an Integer still be reflected once control is returned to the first function?
primaryFunc :: SuperType -> MyMap -> (Integer, MyMap)
primaryFunc (SubType1 a) mapInstance = do
let returnInt = func1 a mapInstance
(returnInt, mapInstance)
primaryFunc (SubType2 c) mapInstance = do
let returnInt = primaryFunc_nonprefix_SuperType c mapInstance
let returnSuperType = (Const returnInt)
let returnTable = H.insert c returnSuperType mapInstance
(returnInt, returnTable)
primaryFunc (ConstSubType d) mapInstance = do
let returnInt = d
(returnInt, mapInstance)
func1 :: SubType1 -> MyMap -> Integer
func1 oe vt = do
--do stuff with input and map data to get return int
returnInt = primaryFunc
returnInt
func2 :: SubType2 -> MyMap -> Integer
func2 pe vt = do
--do stuff with input and map data to get return int
returnInt = primaryFunc
returnInt
Your question is almost impossibly dense and ambiguous, but it should be possible to answer what you term your "primary" question from the simplest first principles of Haskell:
No Haskell function updates a value (e.g. a map). At most it can return a modified copy of its input.
Outside of the IO monad, no function can have side effects. No function can affect the value of any variable assigned before it was called; all it can do is return a value.
So if you pass a map as a parameter to a function, nothing the function does can alter your existing reference to that value. If you want an updated value, you can only get that from the output of a function to which you have passed the original value as input. New value, new reference.
Because of this, you should have absolute clarity at any depth within your web of functions about which value you are working with. Knowing this, you should be able to answer your own question. Frankly, this is such a fundamental characteristic of Haskell that I am perplexed that you even need to ask.
If a function only returns an integer, then any operations you perform on any values made available to the function can only affect the output - that is, the integer value returned. Nothing done within the function can affect anything else (short of causing the whole program to crash).
So if function A has a reference to a map and it passes this value to function B which returns an int, nothing function B does can affect A's copy of the map. If function B were allowed to secretly alter A's copy of the map, that would be a side effect. Side effects are not allowed.
You need to understand that Haskell does not have variables as you understand them. It has immutable values, references to immutable values and functions (which take inputs and return new outputs). Functions do not have variables which are in scope for other functions which might alter those variables on the fly. That cannot happen.
As an aside, not only does the code you posted show that you do not understand the basics of Haskell syntax, the question you asked shows that you haven't understood the primary characteristics of Haskell as a language. Not only are these fundamentals things which can be understood before having learned any syntax, they are things you need to know to make sense of the syntax.
If you have a deadline, meet it using a tool you do understand. Then go learn Haskell properly.
In addition, you will find that
an insert on a Map in a function that only returns an Integer
is nearly impossible to express. Yes, you can technically do it like in
insert k v map `seq` 42 -- force an insert and throw away the result
but if you think that, for example:
let done = insert k v map in 42
does anything with the map, you're probably wrong.
In no case, however, is the original map altered.

How can I use clSetKernelArg to set local memory size in an OpenCL Haskell program?

I'm using the System.GPU.OpenCL module by Luis Cabellos to control an OpenCL kernel.
All is working well but to speed things up I am trying to cache some global memory into a local buffer. I have just noticed that it seems to be impossible to pass a local buffer using the current definition of clSetKernelArg, but perhaps someone can enlighten me?
The definition is,
clSetKernelArg :: Storable a => CLKernel -> CLuint -> a -> IO ()
clSetKernelArg krn idx val = with val $ \pval -> do
whenSuccess (raw_clSetKernelArg krn idx (fromIntegral . sizeOf $ val) (castPtr pval))
$ return ()
where the raw function is defined as,
foreign import CALLCONV "clSetKernelArg" raw_clSetKernelArg ::
CLKernel -> CLuint -> CSize -> Ptr () -> IO CLint
Therefore the high level clSetKernelArg conveniently figures out the size of the memory and also extracts a pointer to it. This is perfect for global memory, but it seems that the way to use clSetKernelArg when local memory is requested is to specify the size of the desired memory in the CSize, and set Ptr to zero. Of course, putting nullPtr here doesn't work, so how can I circumvent this problem? I would call raw_clSetKernelArg directly, but it seems it is not exported by the module.
Thanks.
I don't think there's any way to rig up a hack so that pval ends up being a nullPtr.
This seems like a fairly simple omission from the wrapped API; I'd suggest simply reporting it rather than trying to hack around it :)

Resources