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

Mic*_*Fox 6 haskell

newCString :: String -> IO CString
peekCString :: CString -> IO String
Run Code Online (Sandbox Code Playgroud)

你需要

fromString :: String -> a
show :: a -> String
Run Code Online (Sandbox Code Playgroud)

我的跛脚尝试

{-# 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
Run Code Online (Sandbox Code Playgroud)

它似乎工作.但是,从来没有说过unsafePerformIO,我想知道我在这里设置了什么样的灾难?我漏了记忆吗?有这种方便的安全方法吗?

Jon*_*ast 8

show不会.例如,您的功能将CString在不同时间为相同值返回不同的结果.这是因为a CString真的是一个可变的字符串,相当于IORef String.因为当评估表达式并且Haskell语言没有指定表达式的计算次数时,show cs使用您的实例的表达式将具有非确定性值,因此大多数 Haskell程序员会说这不是有效的使用unsafePerformIO,并且它(故意)不可能在Show CString不使用的情况下实施unsafePerformIO.


chi*_*chi 6

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

但是,上述情况只是因为你永远不会释放内存,而是每次分配新的字符串时都会泄漏内存newCString.

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

我强烈建议不要这样做.

TL; DR:

  1. unsafePerformIO 是不安全的,除非你知道自己在做什么,否则不要使用它.
  2. 像C这样的指针CString应该尽可能少地使用,并且只能与外语交互.