CString可以是IsString的一个实例,Show?

时间:2015-07-24 21:05:03

标签: haskell

有' S

newCString :: String -> IO CString
peekCString :: CString -> IO String

你需要

fromString :: String -> a
show :: a -> String

我的跛脚尝试

{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverlappingInstances #-}

module Main where

import Data.String
import Foreign.C.String
import System.IO.Unsafe

instance IsString CString where
  fromString = unsafePerformIO . newCString

instance {-# OVERLAPS #-} Show CString where
  show = unsafePerformIO . peekCString

mycs :: CString
mycs = "hello CString"

main = putStrLn $ show mycs

似乎有效。但是,在我想知道我在这里设置了什么样的灾难之前从未说过unsafePerformIO?我漏了记忆吗?有这种方便的安全方法吗?

2 个答案:

答案 0 :(得分:8)

没有。例如,您的show函数会在不同时间为相同的CString值返回不同的结果。这是因为CString实际上是一个可变字符串,相当于IORef String。因为当评估表达式并且Haskell语言未指定表达式的计算次数时,使用您的实例的表达式show cs将具有非确定性值,因此大多数 Haskell程序员会说这不是unsafePerformIO的有效用法,并且(有意)不使用Show CString来实现unsafePerformIO

答案 1 :(得分:6)

这可能在技术上是安全的,因为您永远不会更改CString值指向的内存。因此,这些值确实是不可变的,unsafePerformIO的效果只是模仿一个纯值。

然而,以上只是因为你永远不会释放内存,而只是在每次用newCString分配新字符串时泄漏它。

只要使用free修复内存泄漏,就会失去安全性:unsafePerformIO将读取旧内存地址中找到的内容。如果运气好的话,这会导致程序崩溃。如果你运气不好,这会将垃圾数据读入你的字符串。祝你好好调试。

我强烈建议不要这样做。

TL; DR:

  1. unsafePerformIO不安全,除非您知道自己在做什么,否则不要使用它。
  2. 应尽可能少地使用类似C的指针,例如CString,并且只能与外语交互。