Search code examples
haskelltypesmoduleioc-strings

Haskell beginner how did I get to IO ( IO String )


So I got it into my head to learn me some Haskell (boriing night shifts), and I put together a program that can ease my vacation planning by being able to calculate my shift for any giving period.

import System.Environment
import Data.List
import Data.List.Split
import Data.Time
import Data.Time.Calendar.WeekDate (toWeekDate)


-- merge xs and ys lists alternating value from each [ xs(0),ys(0),(xs(1),ys(1)..xs(n),ys(n) ]
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : merge xs ys     

-- get part of list from index 'start' to 'stop'
slice :: Int -> Int -> [a] -> [a]
slice start_from stop_at xs = fst $ splitAt (stop_at - start_from) (snd $ splitAt start_from xs)

timeFormat = "%d-%m-%Y"
timeFormatOut :: Day -> String
timeFormatOut = formatTime defaultTimeLocale "%d-%m-%Y" 
-- parses Strings to DateTime Day1
parseMyDate :: String -> Day
parseMyDate = parseTimeOrError True defaultTimeLocale timeFormat

-- 8 week shift rotation
shiftRotation = cycle ["NAT","NAT","NAT","NAT","NAT","NAT","NAT","-","-","-","-","-","-","-","DAG","DAG","DAG","DAG","-","AFT","AFT","-","-","DAG","DAG","DAG","-","-","DAG","DAG","DAG","-","DAG","DAG","DAG","DAG","DAG","-","DAG","DAG","-","-","AFT","AFT","AFT","AFT","AFT","-","-","DAG(r)","DAG(r)","DAG(r)","DAG(r)","DAG(r)","(r)","(r)"]

hs_findshift :: String -> String -> String -> IO String
hs_findshift anchor start end = do
    let dayZero = parseMyDate anchor
    let startDate = parseMyDate start
    let endDate = parseMyDate end
    let startPos = fromIntegral (diffDays startDate dayZero)
    let endPos = fromIntegral (diffDays endDate dayZero) + 1
    let period = slice startPos endPos shiftRotation
    let dates = map (timeFormatOut) [startDate..endDate]
    let listStr = (concat(intersperse "," (merge dates period)))
    putStrLn listStr

This works nicely. Now I throught I'd try and export it to a C# app so I could make a nice interface. I'm having some trouble with the it. I added

module Shiftlib where

import Foreign.C.String
import Foreign.C.Types

to the top. Right under the imports I added a block to convert inputs and outputs to C types.

foreign export ccall findshift :: CString -> CString -> CString -> IO CString

findshift :: CString -> CString -> CString -> IO CString
findshift a s e = do
    anchor <- peekCString a
    start <- peekCString s
    end <- peekCString e
    result <- hs_findshift anchor start end
    return $ newCString result

now it doesn't compile. It seems that "return $ newCString result" returns an IO ( IO CString ) which the "foreign" call wont accept.

:l shiftlib
[1 of 1] Compiling Shiftlib         ( shiftlib.hs, interpreted )
shiftlib.hs:53:1: error:
    * Illegal foreign declaration: requires unregisterised, llvm (-fllvm) or native code generation (-fasm)
    * When checking declaration:
        foreign export ccall "findshift" findshift
          :: CString -> CString -> CString -> IO CString
   |
53 | foreign export ccall findshift :: CString -> CString -> CString -> IO CString
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

shiftlib.hs:61:5: error:
    * Couldn't match type `IO CString' with `GHC.Ptr.Ptr CChar'
      Expected type: IO CString
        Actual type: IO (IO CString)
    * In a stmt of a 'do' block: return $ newCString result
      In the expression:
        do anchor <- peekCString a
           start <- peekCString s
           end <- peekCString e
           result <- hs_findshift anchor start end
           ....
      In an equation for `findshift':
          findshift a s e
            = do anchor <- peekCString a
                 start <- peekCString s
                 end <- peekCString e
                 ....
   |
61 |     return $ newCString result
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

I cant seem to get around it. How can I return a CString from my little module?


Solution

  •                 newCString :: String -> IO String
                        result :: String
             newCString result ::           IO String
                        return ::                   a -> IO a
    return $ newCString result ::                        IO (IO String)
    

    Simply stop when you already have the thing you want, newCString result.